こんにちは、開発本部の宮内です。 さて、これまで弊社のオンライン診療アプリ「 CLINICS 」では、ローンチ時より Heroku を利用しておりました。 Heroku とは、PaaS の一種で Web アプリケーションを簡単にデプロイ、ホスティングできるサービスです。 ある程度の制約はつきますが、(大体の制約は金で解決できるので)使っているかたも多いのではないでしょうか。 今回、事情により Heroku から AWS Elastic Beanstalk (以下、EB)へ移行することになりましたので、そのあたりでやったことを共有できればと思います。 Private PaaS にしないの? まずはじめに移行にあたり、Priavte PaaS を構築する方法を模索しました。 ですが、これらのクラスタの構築はできても、専任の(Ops|SRE|インフラ)チームがいないため、日々の管理や運用に手が回らないだろうという思いから、Private PaaS の構築は見送りました。 この辺りは今後チーム人数が増えたら挑戦していきたいです…。 検討時、参考にしたリンク PAAS comparison - Dokku vs Flynn vs Deis vs Kubernetes vs Docker Swarm (2017) Convox Deis Flynn なぜ AWS Elastic Beanstalk にしたの? EB には Rails や Sinatra で作成されたウェブアプリケーションを実行するための Ruby プラットフォーム が予め用意されております。 ただし、今回の移行では、アプリケーションへの変更を一切加えずに行いたかったため、Ruby プラットフォームを利用しませんでした。 代わりに Docker コンテナが実行できる プラットフォーム があったため、そちらを使うことにしました。 herokuish で Docker イメージを作成 アプリケーションの Docker イメージ化には、 gliderlabs/herokuish を使いました。 これは buildpack を使いアプリケーションを slug 化したり、slug を実行するためのツールです。 Docker イメージ作成の手順は以下の通りです。 herokuish buildpack build と herokuish slug generate でアプリケーションを slug にする herokuish slug import で slug をインポートして完成 それでは、それぞれ簡単に説明していきたいと思います。 アプリケーションを slug にする docker pull gliderlabs/herokuish docker run \ -v "/path/to/app:/tmp/build" \ -v "/path/to/cache:/tmp/cache" \ -v "/path/to/slug:/tmp/slug" \ gliderlabs/herokuish \ /bin/bash -c 'herokuish buildpack build && herokuish slug generate && herokuish slug export > /tmp/slug/slug.tgz' herokuish は特定のディレクトリに対して処理を行います。↑ ではビルドするアプリケーションまでのディレクトリパスを /tmp/build にマッピングしています。 /tmp/cache は buildpack が利用するキャッシュ置き場です。このディレクトリを次回以降のビルドでもマッピングしておくとビルドの高速化が見込めます。 最後の /tmp/slug はビルドした slug をコンテナからホストへコピーするために指定しています。(これは herokuish で用意されてるものではなくコンテナからホストへファイルをコピーする方法を悩んだ末のアドホックな対応です…) 他にも様々なディレクトリがあります。詳しくは ドキュメント をご覧ください。 slug をインポートする 次に作成した slug を使いアプリケーションの Docker イメージをつくります。 cd $( mktemp -d ) mv /path/to/slug/slug.tgz . echo ' FROM gliderlabs/herokuish COPY slug.tgz /tmp/slug.tgz RUN cat /tmp/slug.tgz | herokuish slug import && rm /tmp/slug.tgz EXPOSE 5000 ' > Dockerfile docker build -f Dockerfile . docker build 時に Context としてカレントディレクトリ全体が送られるため、一時ディレクトリを作成しその中で docker build を行っています。 終わり CLINICS では上記のような手段で作成した Docker イメージを Amazon EC2 Container Registry にアップロードし EB 上で実行しています。 本来であれば、アプリケーションを slug にする部分と、slug をインポートする部分を分割しなくても良いと思いますが、CircleCI で Docker イメージを作成する関係上でこのような方法になりました。 先日 GA となった CircleCI 2.0 にはまだ対応できていないので、今後の課題としたいと思います。 お知らせ メドレーでは、CLINICS だけでなく、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは、開発本部の宮内です。 さて、これまで弊社のオンライン診療アプリ「 CLINICS 」では、ローンチ時より Heroku を利用しておりました。 Heroku とは、PaaS の一種で Web アプリケーションを簡単にデプロイ、ホスティングできるサービスです。 ある程度の制約はつきますが、(大体の制約は金で解決できるので)使っているかたも多いのではないでしょうか。 今回、事情により Heroku から AWS Elastic Beanstalk (以下、EB)へ移行することになりましたので、そのあたりでやったことを共有できればと思います。 Private PaaS にしないの? まずはじめに移行にあたり、Priavte PaaS を構築する方法を模索しました。 ですが、これらのクラスタの構築はできても、専任の(Ops|SRE|インフラ)チームがいないため、日々の管理や運用に手が回らないだろうという思いから、Private PaaS の構築は見送りました。 この辺りは今後チーム人数が増えたら挑戦していきたいです…。 検討時、参考にしたリンク PAAS comparison - Dokku vs Flynn vs Deis vs Kubernetes vs Docker Swarm (2017) Convox Deis Flynn なぜ AWS Elastic Beanstalk にしたの? EB には Rails や Sinatra で作成されたウェブアプリケーションを実行するための Ruby プラットフォーム が予め用意されております。 ただし、今回の移行では、アプリケーションへの変更を一切加えずに行いたかったため、Ruby プラットフォームを利用しませんでした。 代わりに Docker コンテナが実行できる プラットフォーム があったため、そちらを使うことにしました。 herokuish で Docker イメージを作成 アプリケーションの Docker イメージ化には、 gliderlabs/herokuish を使いました。 これは buildpack を使いアプリケーションを slug 化したり、slug を実行するためのツールです。 Docker イメージ作成の手順は以下の通りです。 herokuish buildpack build と herokuish slug generate でアプリケーションを slug にする herokuish slug import で slug をインポートして完成 それでは、それぞれ簡単に説明していきたいと思います。 アプリケーションを slug にする docker pull gliderlabs/herokuish docker run \ -v "/path/to/app:/tmp/build" \ -v "/path/to/cache:/tmp/cache" \ -v "/path/to/slug:/tmp/slug" \ gliderlabs/herokuish \ /bin/bash -c 'herokuish buildpack build && herokuish slug generate && herokuish slug export > /tmp/slug/slug.tgz' herokuish は特定のディレクトリに対して処理を行います。↑ ではビルドするアプリケーションまでのディレクトリパスを /tmp/build にマッピングしています。 /tmp/cache は buildpack が利用するキャッシュ置き場です。このディレクトリを次回以降のビルドでもマッピングしておくとビルドの高速化が見込めます。 最後の /tmp/slug はビルドした slug をコンテナからホストへコピーするために指定しています。(これは herokuish で用意されてるものではなくコンテナからホストへファイルをコピーする方法を悩んだ末のアドホックな対応です…) 他にも様々なディレクトリがあります。詳しくは ドキュメント をご覧ください。 slug をインポートする 次に作成した slug を使いアプリケーションの Docker イメージをつくります。 cd $( mktemp -d ) mv /path/to/slug/slug.tgz . echo ' FROM gliderlabs/herokuish COPY slug.tgz /tmp/slug.tgz RUN cat /tmp/slug.tgz | herokuish slug import && rm /tmp/slug.tgz EXPOSE 5000 ' > Dockerfile docker build -f Dockerfile . docker build 時に Context としてカレントディレクトリ全体が送られるため、一時ディレクトリを作成しその中で docker build を行っています。 終わり CLINICS では上記のような手段で作成した Docker イメージを Amazon EC2 Container Registry にアップロードし EB 上で実行しています。 本来であれば、アプリケーションを slug にする部分と、slug をインポートする部分を分割しなくても良いと思いますが、CircleCI で Docker イメージを作成する関係上でこのような方法になりました。 先日 GA となった CircleCI 2.0 にはまだ対応できていないので、今後の課題としたいと思います。 お知らせ メドレーでは、CLINICS だけでなく、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
こんにちは、開発本部の宮内です。 さて、これまで弊社のオンライン診療アプリ「 CLINICS 」では、ローンチ時より Heroku を利用しておりました。 Heroku とは、PaaS の一種で Web アプリケーションを簡単にデプロイ、ホスティングできるサービスです。 ある程度の制約はつきますが、(大体の制約は金で解決できるので)使っているかたも多いのではないでしょうか。 今回、事情により Heroku から AWS Elastic Beanstalk (以下、EB)へ移行することになりましたので、そのあたりでやったことを共有できればと思います。 Private PaaS にしないの? まずはじめに移行にあたり、Priavte PaaS を構築する方法を模索しました。 ですが、これらのクラスタの構築はできても、専任の(Ops|SRE|インフラ)チームがいないため、日々の管理や運用に手が回らないだろうという思いから、Private PaaS の構築は見送りました。 この辺りは今後チーム人数が増えたら挑戦していきたいです…。 検討時、参考にしたリンク PAAS comparison - Dokku vs Flynn vs Deis vs Kubernetes vs Docker Swarm (2017) Convox Deis Flynn なぜ AWS Elastic Beanstalk にしたの? EB には Rails や Sinatra で作成されたウェブアプリケーションを実行するための Ruby プラットフォーム が予め用意されております。 ただし、今回の移行では、アプリケーションへの変更を一切加えずに行いたかったため、Ruby プラットフォームを利用しませんでした。 代わりに Docker コンテナが実行できる プラットフォーム があったため、そちらを使うことにしました。 herokuish で Docker イメージを作成 アプリケーションの Docker イメージ化には、 gliderlabs/herokuish を使いました。 これは buildpack を使いアプリケーションを slug 化したり、slug を実行するためのツールです。 Docker イメージ作成の手順は以下の通りです。 herokuish buildpack build と herokuish slug generate でアプリケーションを slug にする herokuish slug import で slug をインポートして完成 それでは、それぞれ簡単に説明していきたいと思います。 アプリケーションを slug にする docker pull gliderlabs/herokuish docker run \ -v "/path/to/app:/tmp/build" \ -v "/path/to/cache:/tmp/cache" \ -v "/path/to/slug:/tmp/slug" \ gliderlabs/herokuish \ /bin/bash -c 'herokuish buildpack build && herokuish slug generate && herokuish slug export > /tmp/slug/slug.tgz' herokuish は特定のディレクトリに対して処理を行います。↑ ではビルドするアプリケーションまでのディレクトリパスを /tmp/build にマッピングしています。 /tmp/cache は buildpack が利用するキャッシュ置き場です。このディレクトリを次回以降のビルドでもマッピングしておくとビルドの高速化が見込めます。 最後の /tmp/slug はビルドした slug をコンテナからホストへコピーするために指定しています。(これは herokuish で用意されてるものではなくコンテナからホストへファイルをコピーする方法を悩んだ末のアドホックな対応です…) 他にも様々なディレクトリがあります。詳しくは ドキュメント をご覧ください。 slug をインポートする 次に作成した slug を使いアプリケーションの Docker イメージをつくります。 cd $( mktemp -d ) mv /path/to/slug/slug.tgz . echo ' FROM gliderlabs/herokuish COPY slug.tgz /tmp/slug.tgz RUN cat /tmp/slug.tgz | herokuish slug import && rm /tmp/slug.tgz EXPOSE 5000 ' > Dockerfile docker build -f Dockerfile . docker build 時に Context としてカレントディレクトリ全体が送られるため、一時ディレクトリを作成しその中で docker build を行っています。 終わり CLINICS では上記のような手段で作成した Docker イメージを Amazon EC2 Container Registry にアップロードし EB 上で実行しています。 本来であれば、アプリケーションを slug にする部分と、slug をインポートする部分を分割しなくても良いと思いますが、CircleCI で Docker イメージを作成する関係上でこのような方法になりました。 先日 GA となった CircleCI 2.0 にはまだ対応できていないので、今後の課題としたいと思います。 お知らせ メドレーでは、CLINICS だけでなく、医療介護の求人サイト「 ジョブメドレー 」、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
はじめまして!最近みるみる太りだしてはいるものの、まだ機は熟していないとダイエットの時期をぐっと堪えている開発本部イケメン担当のデザイナー・小山です。 メドレーでは TechLunch という社内勉強会を実施しているのですが、 前田 に引き続き私も発表する機会をいただきましたので、その内容を紹介させていただきます。テーマは「思考とデザインスキル」です。発表資料は記事の最後をご覧ください。 テーマに入るまえに… みなさん『黄金比』ってご存知ですか? 黄金比は美しいとされる物の形に共通してみられる比率で、古くから絵画や彫刻、建築などに使われています。デザイナーであれば、一度以上は使ったことあるのではないでしょうか?私もデザイナーなので何度も使っています。 ただ使ってはいるものの、なぜ美しくなるのか上手く説明ができません。当たり前のように世の中に広まっていて『困ったときの黄金比!』といった安易な思考で使っています。三十路を軽く超えたのでそれではいけないと思い、すこし調べてみました。 そもそも黄金比はエウクレイデスというユーグリッド幾何学を体系化した数学者が見つけた比率なのですが、そのとき彼は『黄金比=美しい』とは明言していないそうです。自然物や人工物の形には一定の比率で成り立っていると考え、その比率に黄金比と名付けだけとのこと。 その後、その使いやすさから至るところで活用され、その比率に親しみが芽生え巷で受け入れられるようになりました。 認知心理学では、それを『 単純接触効果 』と呼びます。たくさん触れるうちに親しみが沸く機能が人にはもともと備わっていて、黄金比をつかったものが美しく見えるのもその影響ではないか?と言われています。この説を聞いた時、基礎的なのに原理が曖昧なデザイナーのスキルの輪郭がすこしだけハッキリしてきました。 今回の TechLunch では、曖昧だったデザインのスキルを人の思考や心理現象という視点から捉え直してみると、新しい発見があるのかも?と考え、『思考とデザインスキル』のテーマを選びました。 『早い思考』と『遅い思考』 まず最初に人の思考がどういう構造になっているか整理したいと思います。 *思考の捉え方には幅があるため、今回は Wikipedia で【思考】の狭義にあたる『情報処理』の内容になります。 ここで 3 つの質問を左から順に答えてください。 大抵の人であれば 2 問目までは瞬時に答えが出たと思います。3 問目はどうでしょうか? 3 問目は他よりも時間がかかったかと思います。情報を処理するときの思考には 1 問目と 2 問目のように瞬時に答えれるのは『 早い思考 』、3 問目のように少し時間は必要な『 遅い思考 』の 2 つがあります。 行動経済学では、この早い思考を『 システム 1 』、遅い思考を『 システム 2 』と呼んでいます。 システム 1 は、自動的に直感で動く では次にこちらをご覧ください。 どちらの直線が長いでしょうか?答えはどちらも同じです。この問題をご存知の方でも見た瞬間は A が長く見えるのではないでしょうか? ではこちらではどうでしょうか? こちらの文字をみたときに、海水浴していて溺れている、もしくはそれに近いシーンを思い浮かべてないでしょうか? この二語のあいだには『りんご あまい』というような直接の相関はありません。それにもかかわらず出来れば避けたくなるようなことでも無意識に関連づけられ、シーンが思い浮かんだはずです。 システム 1 には、さきほどの直線の長さのように間違っていたとしても『 見たまま 』を認識する機能と 2 つの文字から『 関連づけ 』をおこないストーリーを組み立てる機能があります。そのどちらもが自分の意識とは関係なく自動で、しかも強力に働いています。 システム 2 は、手動で論理的に動く 最初の二桁の掛け算を思い出してください。日本で算数を学んだ人であれば、二桁の掛け算のとき『考える』段階に移ると思います。これがシステム 2 のスイッチです。システム 1 は常時スイッチが入っていてほぼ自動で答えを出しますが、システム 2 は意識的に『考える』というステップを踏まないと動きません。システム 1 は自動ですが、システム 2 は手動です。 手動のため手間かかりますが、システム 1 にはない用心深さと慎重さがあります。こちらの問題をご覧ください。 『 バットとボールで 110 円、バットはボールより 100 円高い、ボールの値段は? 』 即答で答えた人は 10 円と答える方が多いようです。こういう問題にはシステム 2 がうってつけで、論理的かつ正確に答えを出そうとします。答えは 5 円です。なかには頭の回転が早く即答できる人がいらっしゃることだと思います。そんな方にはこちらの問題を答えていだだきましょう。 3 日前から食べた夕飯の献立を口に出して発表しながら、『26x673』『245x287』『346x4546』の 3 問を 90 秒以内に解答してください。 いかがでしょうか?システム 2 は手動でうごき論理的で正確に答え出そうとしますが、複雑すぎる演算やマルチタスクにめっぽう弱くスタミナもありません。あきらめて電卓を叩いた方は、システム 2 がギブアップしたということかもしれません。 システム 1 と 2 の特徴は以下。どちらも良いところとそうでないところがあります。 デザインを再構築 これらシステム 1&2 の特性を踏まえた上で簡単なニュース記事のタイポグラフィを整理してみました。 発表資料の 58 ページからご覧ください。 speakerdeck.com こと細かく情報をシステム 1&2 のフィルターを通すことで、タイトルやリード、本文の行間、文字サイズ、それらがシステム 2 が情報を理解しやすくするための1つ機能として捉えることができます。当たり前に使っていたスキルや機能を別の視点で捉えることで違った深い意味を見出せるようになり、大きな発見につながりました。 今回はタイポグラフィだったのでシステム 2 寄りのものでしたが、ビジュアルアイデンティティが強く抽象的なデザインは、意図的にシステム 2 を封じ込めシステム 1 の直感性を利用して内容を理解してもらうこともできます。 システム 1&2 の 2 つの特性を踏まえて使いこなすことで、スキルの深い理解はもちろんですが、感覚とは違うデザインの伝え方の新しいヒントにもなりそうです。 さいごに YouTube や Instagram、LINE はどちらかというと直感性を促すシステム 1 が活躍するアプリです。それだけでなく身の回りにあるサービス全体がその傾向という印象をうけます。システム 1 は普段からスイッチが入っているため、比較的に簡易なステップで働きかけることができます。 一方でシステム 2 は複雑な演算には耐えれず、しっかりとケアしながらでないと十分な運用ができません。ただケアをしっかりすると恩恵も大きいといえます。 金融、教育、雇用、そして医療と、20 年前とは比較にならないほどインターネットは人生の節目に深く関わるようになったからです。人生に関わる選択をネットで行うとき、 直感だけでなくシステム 2 を働かせて熟考し納得のいく決断を行うことが、よりユーザーの利益につながる と私は考えています。 メドレーで提供しているサービスはユーザーの人生に少なからず関わる性質をもっています。すぐに結論づけしてもらうより、ユーザーにとって正しいと思える判断ができるように、 システム 2 をうまく働かせることができる環境をデザイナーとしてつくっていきたい と思います。 おまけ 今回のテックランチで参考にさせていただいた書籍は以下のものになります。 『 ファスト&スロー(上・下) 』ダニエル・カーネマン 『 予想通りに不合理 』ダン・アリエリ 『 錯覚の科学 』クリストファー・チャブルス&ダニエル・シモンズ 『 UI デザインの心理学 』ジェフ・ジョンソン 今回のお話は、本当に本当に表面の部分になります。流し読みでも参考になるので手に取って見てください。またこういうことに興味がわいたデザイナーさん・エンジニアさん、是非是非メドレーに遊びに来てください!(絶賛募集中です!) お知らせ メドレーでは、ジョブメドレーだけでなく、医師たちがつくるオンライン医療事典「 MEDLEY 」やオンライン診療アプリ「 CLINICS 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトも提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 www.medley.jp 今後ともメドレーを、よろしくお願いいたします!
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 https://www.medley.jp/recruit/creative.html
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があることで苦労した点もあり( 前編参照 )、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます。 前編では Proxy 層の構成として、主に Nginx を使用した Path Based Routing 周りについてのお話でした。後編では App 層で使用した EC2、 Systems Manager パラメータストアあたりについて共有いたします。 App 層の構成 App 層の方針や構築の流れ等をまとめると以下の通りです。 ゴールデンイメージとして OS 設定やサーバアプリケーションをインストールした image(AMI)を作成しておく 上記の AMI を元に、クライアント毎に EC2 インスタンスを作成する インスタンス作成時に必要な Tag の値や環境変数を設定しておく 環境変数はパラメータストアに登録 EC2 インスタンス起動時に、クライアントに応じた Tag や環境変数をもとにサーバアプリケーションのセットアップを行う 自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する それでは、それぞれの詳細について説明していきたいと思います。 AMI 作成 Packer を使用して各インスタンス共通となる AMI を作成します。 provisioners で指定した構築用スクリプトで OS 設定や必要ライブラリ、またメインとなるサーバアプリケーションをインストールします。また、cloud-init を使用して初回起動時に動かすスクリプト類もコピーしておきます。 なお、cloud-init から実行するスクリプトは Git や S3 などから動的に取得する方法もありますが、さほどスクリプトの内容に変更は発生しない点と、内容的に変更ある場合は image 再作成がどちらにしても必要になりそうだったので割り切って image 内に含めることにしています。 作成した packer.json の provisioners 部分を抜粋するとこのような感じになります(説明コメント部分は実際には記載していません) "provisioners" : [ -- type: shell として、構築用スクリプト指定。ビルド時に実行される { "type" : "shell" , "scripts" : [ "scripts/provision.sh" ] }, -- type: file でインスタンス起動時に実行させるスクリプト群をコピー -- これらのスクリプトは cloud-init から実行される(cloud-init の設定は別途インスタンス作成時に行っている) { "type" : "file" , "source" : "./scripts" , "destination" : "/home/hoge" }, -- 上記のスクリプトに対して実行権限付与 { "type" : "shell" , "inline" : [ "chmod +x /home/hoge/scripts/*" ] } ] packer build でビルドした image が AWS に今回の共通で使用する AMI として登録されます EC2 インスタンス作成 作成した AMI を元に、クライアントごとのインスタンスを作成します。なお、インスタンス作成は Terraform や CloudFormation などは使わず、AWS CLI を利用したスクリプトを作成して実行しています。 インスタンス作成スクリプトはこのような流れの処理となります。 引数でクライアント識別 ID やその他サーバアプリケーションセットアップに必要となる環境変数を指定 AWS CLI で EC2 インスタンス作成 引数で指定された環境変数を AWS CLI でパラメータストアに登録 インスタンス作成 以下のように、 aws ec2 run-instances コマンドを使用し、Tag にクライアント識別 ID を指定して作成しています。 ここで指定したクライアント識別 ID を元にパラメータストアから自分用の環境変数を登録/取得したり、Private DNS 用のドメインに使用します。 aws ec2 run-instances \ --image-id ${ AMI_ID } \ --key-name ${ KEY_NAME } --region ${ REGION } \ --subnet-id ${ SUBNET_ID } \ --security-group-ids ${ SECURITY_GROUP } \ --user-data file:// ${ USER_DATA } \ --instance-type ${ INSTANCE_TYPE } \ --tag-specifications "ResourceType=instance,Tags=[{Key=ClientId,Value=${ CLIENT_ID }}]" \ --iam-instance-profile "Arn=${ SERVICE_ROLE }" user-data には初回起動時に実行したいスクリプト(Packer でビルド時にコピーしておいたスクリプト)を指定しているだけとなります。 #!/bin/bash /home/hoge/scripts/bootstrap.sh パラメータストアに環境変数登録 使用する環境変数は、Key は共通ですが値がクライアントによって異なります。そのため、HOGE という Key を使用する場合、 <クライアント識別 ID>.HOGE という形式でパラメータストアに登録しています。 (注. パラメータストアに 階層やタグ付けがサポートされた らしく、このあたりの構成は今後見直す予定です) 登録は aws ssm put-parameter を実行します aws ssm put-parameter \ --name ${ KEY } \ --value ${ VALUE } \ --type ${ PARAMETER_TYPE } \ # String、SecureString など --overwrite これでクライアントごとの EC2 インスタンスが作成、起動されます。次にインスタンス起動時の流れについてです。 EC2 インスタンス起動 起動時は、初回起動と毎回起動でそれぞれ以下のような処理を行います。 初回: パラメータストアから自身に関連する環境変数を取得し、サーバアプリケーションのセットアップ 毎回: 自身の内部 IP を Route53 の Private DNS に登録/更新 内部 IP は固定しておらず起動時に割り振られるため、毎回更新するようにしています。 それではそれぞれの内容について見ていきます。 パラメータストアから環境変数取得 登録時の内容で記載しましたが、環境変数は <クライアント識別 ID>.HOGE という形式で登録しています。そのため、まずは自身のクライアント識別 ID を判定した後に必要な環境変数を aws ssm get-parameters で取得します。 # 自身のインスタンス ID をメタデータから取得 INSTANCE_ID =$( curl -s https://169.254.169.254/latest/meta-data/instance-id ) # クライアント識別 ID をインスタンス作成時に指定した Tag から取得 # (describe-instances の filter に自身のインスタンス ID を指定) CLIENT_ID_TAG =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].Tags[] | select(.Key == "ClientId").Value' ) # 環境変数を取得 # タイプを SecureString にしている変数もあるため、一律 --with-decryption オプションを指定している HOGE =$( aws ssm get-parameters \ --name "${ CLIENT_ID_TAG }.HOGE" \ --with-decryption --region ${ REGION } \ | jq -r ".Parameters[].Value" ) export HOGE =${ HOGE } 内部 IP を Private DNS に登録 最後に、Proxy 層から Private DNS で名前解決できるように自身の IP を Route 53 に登録してやります。 なお、Route53 には事前に対象の Hosted Zone を Private Hosted Zone for Amazon VPC タイプとして登録しておきます。ここでは例として Domain Name を local とします。 EC2 インスタンスから登録される RecordSet は以下の形式とします。 Name: <クライアント識別 ID>.local Type: CNAME Value: EC2 インスタンスの内部 IP これらを行うスクリプト例は以下となります。 # 内部 IP を取得 # (describe-instances の filter に自身のインスタンス ID を指定) PRIVATE_IP =$( aws ec2 describe-instances \ --region=${ REGION } \ --filters "Name=instance-id,Values=${ INSTANCE_ID }" \ | jq -r '.Reservations[].Instances[].PrivateIpAddress' ) # Route53 の登録先 Hosted Zone ID を取得 # SEARCH_KEY は今回の例でいうと 'local.' になります HOSTED_ZONE_ID =$( aws route53 list-hosted-zones \ --region=${ REGION } \ | jq -r ".HostedZones[] | select(.Name == \" ${ SEARCH_KEY } \" ).Id" ) # この後の登録コマンドで指定するための定義ファイル # 毎起動時の登録用(IP が変わるため)に、Action には 'UPSERT' を指定 RECORDSET_FILE = "/tmp/create_recordset.json" cat << EOT > ${ RECORDSET_FILE } { "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "<クライアント識別 ID>.local", "Type": "CNAME", "TTL": 300, "ResourceRecords": [ { "Value": "${ PRIVATE_IP }" } ] } } ] } EOT # 作成した定義ファイルを指定し、Route53 に登録 aws route53 change-resource-record-sets \ --hosted-zone-id ${ HOSTED_ZONE_ID } \ --change-batch file:/// ${ RECORDSET_FILE } 実行するステップはやや多いですが、このような構成をとることで VPC 内ではドメイン指定でのアクセスが可能となるため、IP を意識する必要がなくなるため柔軟な構成になるかと思います。 今回のまとめ いまさらインスタンス立てるとかめんどくさいなぁ、、、とか思いながら色々調べて構築しましたが、EC2 まわりのサービスも増えてるんだなぁ、なんて感じました(特にパラメータストアはとても便利) パラメータストア以外にも Systems Manager には Run Command や Patch Manager など EC2 インスタンスを管理する上でとても便利な仕組みが揃っていますのでこのあたりも導入していきたいと思います。 余談ですが、Systems Manager の存在は re:Invent 2016 で発表された時から名前だけは知ってましたが、今回の対応するまでずっとオンプレ専用のサービスだと勘違いしてて記憶から消えかけていました。。。 最後に 前編を Proxy 層 (Nginx)、後編を App 層(EC2)について書かせていただきましたがいかかだったでしょうか。 そもそもの要件自体がけっこう特殊だったりもするので、なんでこんな構成に?みたいなとこもあるかも知れませんが、どなたかの参考になれば幸いです。もう少し聞いてみたい、というかたは wantedly の「 話を聞いてみたい 」ボタンからどうぞ。 ※前編をあらためて読みたい方はこちらからどうぞ https://developer.medley.jp/entry/2017/08/24/120000_01 お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
今回の内容について メドレー開発本部の 田中 です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、後述する制約から苦労した点もあり、制約を乗り越えるための工夫も含めてお話できる限り共有させていただきます(先にお伝えしておくと、特殊な事情がなければ今回のようなケースでは ALB で対応する ECS サービスに Path Based Routing してやるのが良いと思います)。 技術要素として、Nginx(OpenResty)/ Route53 Private DNS / EC2 / Systems Manager パラメータストア あたりに触れたいと思います。(Beanstalk は Multicontainer Docker を使用し、それも慣れるまでちょっとクセあったなぁと思ったのですが分量が多くなりそうなのでまた別の機会に共有させて頂きます) まず前編として Proxy 層、主に Nginx を使用した Dynamic Path Based Routing についてお話して、 後編は App 層 について、EC2 と Systems Manager パラメータストアあたりについて共有させていただければと思います。 設計/構築する上での前提と方針 対象となる案件を進める上での要件・制限内容は諸事情あり、ざっとまとめるとこのような感じです。 環境は AWS を使用する サーバアプリケーション、クライアントアプリケーションはユーザ毎で、サーバアプリケーションは共用できない(ユーザが増える度にクライアント/サーバのセットが増えるイメージ) ただし、クライアントからの接続先となる Endpoint は同じだが、Host Based Routing は訳あって利用できない クライアント認証を使用する 上記から、以下の設計方針で進める事にしました。 Proxy 層でクライアント認証を行い、Path Based Routing で対象となるサーバにリクエストを proxy する。Path 部分にクライアント別の識別 ID を含め、その値を元に Private DNS で名前解決する 例) https://example.com/a-client/api => https://a-client.local/api App 層は個別 EC2 インスタンスとする 設計する上で悩んだ点 主に 2 点ありますが、まずは Proxy 層です。出来るだけ AWS のマネージド・サービスで済ませたかったので、クライアント認証と Path Based Routing が可能でやりたい事に合うかどうか調べましたが以下の理由で断念し、普通(?)に ELB + Nginx を利用することにしました。 ALB: クライアント認証に非対応。また SSL 終端となるので Nginx 側でクライアント認証が出来ない API GW: クライアント認証は対応しており Routing 部分もがんばればいけるかも?、と思ったが Proxy 先が動的に増えたリするので管理ふくめ難しそうであった 次に App 層の構成をどうするかでした。集積度を高めるためにコンテナ利用も検討したのですが、使用するアプリケーションの必要スペックや要件などからいまいちフィットせず、個別の EC2 インスタンスにすることにしました(今でももっと良い方法がないか悩んでたりします) 全体構成 出来上がった全体構成のイメージは以下となります。なお台数は実環境と異なり、今回の内容と関係ない部分などは省略しています。 次に、今回の本題となる Proxy 層の構成について触れたいと思います。 Proxy 層の構成 Proxy 層の方針等はまとめると以下の通りで、proxy 先の動的判定と名前解決する箇所がキモとなります。 App 層のインスタンスは、起動時に自身の内部 IP と Tag に設定したクライアント識別 ID を元に Route53 の PrivateDNS に登録する クライアント識別 ID が a-client の場合、a-client.local のように登録 Proxy 層の Nginx はクライアント認証を行い、リクエストパスから取り出したクライアント識別 ID を元に転送先 Endpoint を生成し、backend に proxy する App 層のインスタンスは動的に増えるため、リクエスト時に名前解決したい(インスタンスが増える度に自動で Nginx の conf を編集することも検討したが追加数が読めず、conf がふくれあがるのもなぁ、、、という思いがあり止めました) Nginx は backend が増えても起動しっぱなしで動的に名前解決して動作させたかったため、lua-nginx-module を導入し balancer_by_lua ディレクティブと lua-resty-dns モジュールを使用することとし、構築の手間の関係から OpenResty を導入することにしました。 lua-nginx-module を使用した conf ファイル conf ファイル全体としては以下となります(関係ない箇所は省いています)。ポイントと記載した部分についての説明は後述します。 http { upstream app { # ポイント 1. # Private DNS で設定した IP(CNAME に設定)を元に動的 Routing balancer_by_lua_block { local balancer = require "ngx.balancer" local host = ngx . ctx . upstream_server . cname local port = '8888' local ok , err = balancer . set_current_peer ( host , port ) if not ok then return ngx . exit ( 500 ) end } } server { listen 443 ssl; set $ proxy_upstream_host '' ; set $ proxy_upstream_domain '.local' ; location ^~ /api/ { rewrite_by_lua_block { -- path からクライアント識別 ID を取得し、Private DNS に設定したドメインを生成 -- https://example.com/<id>/api という形式のリクエストから、<id>.local というドメインを生成して -- ngx.var.proxy_upstream_host 変数に格納 local ngx_re = require "ngx.re" local res , err = ngx_re . split ( ngx . var . request_uri , "/" , nil , { pos = 0 }) local id = res[3] ngx.var. proxy_upstream_host = id..ngx.var.proxy_upstream_domain; -- resolver 設定 local resolver = require "resty.dns.resolver" local r, err = resolver:new{ nameservers = {{ "x.x.x.x" , 53}}, -- 使用する nameserver } if not r then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end -- ポイント 2. -- 生成したドメイン名(<id>.local)を元に名前解決し、取得した結果を ngx.ctx にセット -- (balancer_by_lua_block で使用する) local answers, err = r:query(ngx.var.proxy_upstream_host, { qtype = r.TYPE_CNAME }) if not answers then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end if answers.errcode then ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) end ngx.ctx.upstream_server = answers[1] } 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 $ scheme ; -- https://<id>.local/api に proxy rewrite ^/api/(.+)$ /api/ break; proxy_pass https://app; } } } ポイント 1. 動的 Routing balancer.set_current_peer にて proxy 先を動的に設定します。 host 部分にはドメインを直接指定することができないため、ポイント 2. で ngx.ctx にセットした DNS の値から IP(Route53 に CNAME レコードとして設定している)を指定しています。 balancer_by_lua_block { local balancer = require "ngx.balancer" -- ngx.ctx にセットしていた、Private DNS から取得した内部 IP をセット local host = ngx . ctx . upstream_server . cname local port = '8888' -- proxy 先セット。host にドメインは直接指定できない local ok , err = balancer . set_current_peer ( host , port ) if not ok then return ngx . exit ( 500 ) end } 詳細については OpenResty の ドキュメント を参照してください ポイント 2. 動的名前解決 r:query にて、生成したドメイン名( <id>.local )を問い合わせます。 r 部分は resolver:new で nameserver を指定した resolver となります。 なお、nameserver に指定する IP は今回は Route53 の Private DNS を指定するため、外部 nameserver ではなくローカルの nameserver(10.0.0.2 など)を指定することになります。 問い合わせ結果の answers 部分は Lua table 形式の配列となります。今回の例でいうと対象は 1 件となるので、その値を balancer_by_lua_block で使用するために ngx.ctx にセットしています。 local answers , err = r : query ( ngx . var . proxy_upstream_host , { qtype = r . TYPE_CNAME }) if not answers then ngx . exit ( ngx . HTTP_INTERNAL_SERVER_ERROR ) end if answers . errcode then ngx . exit ( ngx . HTTP_INTERNAL_SERVER_ERROR ) end ngx . ctx . upstream_server = answers [ 1 ] 詳細については OpenResty の ドキュメント を参照してください 今回のまとめ upstream 先を動的に判定して proxy するという要件はそうそう無いかもしれませんし、途中までは複雑な構成になりそうだなぁとドキドキしてしましたが、結果としてはそれなりにシンプルになったかなと思います。今更ながら Nginx(と lua module)は柔軟で良く出来てるなぁという感想でした。 後編は App 層について、EC2 と Systems Manager パラメータストアあたりについて共有させていただければと思います。 クライアント認証と Path Based Routing が必要なサーバを AWS で構築(後編:App 層) | MEDLEY Developer Portal 今回の内容について メドレー開発本部の田中です。 先日、Proxy 層を Elastic Beanstalk 上の Nginx で、App 層を EC2 インスタンスで構築する機会がありました。ここだけ見るととても普通に見えますが、制約があ... developer.medley.jp 参考リンク 構築にあたり、下記記事を参考にさせていただきました。ありがとうございます。 Nginx balancer_by_luaの話とupstream名前解決の話 - Qiita balancer_by_lua_xxxxx いつの間にやら1 lua-nginx-module に balancer_by_lua_xxx という新しいディレクティブが増えていました。 以下ドキュメントより抜粋。 http { upstream backend {... qiita.com お知らせ メドレーでは、医師たちがつくるオンライン医療事典「 MEDLEY 」、オンライン診療アプリ「 CLINICS 」、医療介護の求人サイト「 ジョブメドレー 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 メドレーで一緒に医療体験を変えるプロダクト作りに関わりたい方のご連絡お待ちしております。 メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp