リソグラフ作品を通して、先入観とステレオタイプを感じて考える展示 "Don't Pay for Me" に行ってきた
いまFabCafe Tokyoで開催中の Don't Pay for Me という展示にお邪魔してきました。
大学の後輩でもある友人がアーティストの1人として参加していて、お誘いいただいたのがきっかけなのですが、思うことがたくさんある展示で楽しかったです。とくに最近は、組織文化やコミュニケーションについて考えることが多いので、人の認識や解釈の違い、コミュニケーションの齟齬に関連するトピックで様々な視点を得られたことは個人的に大きな収穫でした。せっかくなので感想を忘れないうちに文字起こししていたら、あれよあれよという間に膨らんでいったので記事にしました。
この展示は、日常的な生活や会話に潜む先入観やステレオタイプについて、国内外30人のアーティストが作品を描くというものです。タイトルの "Don't Pay for Me(私の分払わないでよ)"
は、知人やパートナーと食事にいったときに時折発生する「あれ、どっちが払うの?」という問題から、「そういうものだから」という理由で払わないことになる側の違和感がモチーフになっています。
私はパートナーと食事に行き、数日前の出来事で盛り上がり、お会計を頼む。。。そこには「性」や「立場」に対する社会的な固定概念がある。ジェンダー間の平等を進めると、人は自由になれる。 引用元: リソグラフ展示: ”Don’t Pay for Me”
もしかすると、ジェンダー問題が絡むタイトルから、思想的な要素の強い展示に見えて敬遠される方もいらっしゃるかもしれませんが、そういった意図の展示ではないということを先にお伝えしておきます。ジェンダー間にある不平等をテーマにした作品もありますが、それは一つのトピックでしかありません。展示のコンセプトは先入観やステレオタイプです。それを、異なる視点で、異なるトピックについて、アーティストの人たちが作品として描き出しています。
それぞれの作品がどれも素敵なのですが、共通しているのは表現のバランスが絶妙であるということです。どこに先入観やステレオタイプが潜んでいるのかはわかる程度に具体性があり、しかし解釈や感想が分かれる程度には曖昧というなんともいえない塩梅になっています。好きな作品を探すのも楽しいですが、全ての作品をじっくり眺めるのもおすすめです。いろいろ感じたり考えたりしたあとで、もう一周すると1度目とは見え方が変わったりという楽しさもあるかもしれません。
そして、この展示をさらに楽しむ方法は、誰かと感じたことや考えたことを互いに共有してみることです。特に、性別や立場など、社会的な特性の異なる人と感想を共有しあうと、いろいろな発見があるはずです。
大事なのはこの展示がリソグラフの鮮やかな発色のように、展示作品を見てくださる一人一人に以前自分が感じた不平等を誰かに話したいと、会話の種をつくること。
展示のWebサイトにあるこの一文にもありますが、「作品を通して誰かと話すこと」は、この展示の狙いの一つでもあります。
この体験のデザインが個人的にはとてもハマりました。まずそれ自体が面白いということに加え、人間関係における最も原始的な課題である「コミュニケーション不足」にアプローチしているのがとても好きなポイントです。
人は皆違うので、何もせずに他者の感情や考えを完全に知ることはできません。もちろん、表情や行動、経験的なパターン、あるいは一般的な通説などの情報から推測することは可能です。しかしそれは、相手から直接聞いたものではありません。もしかしたら、もしかしたら、もしかしたら...そうやって推測を重ねて、相手の考えていることとは全く違う結論を出してしまうというのはよくある話です。
感じ方や考え方の違いを認識することは、対話を始める絶好の機会になります。日常の出来事の中で違いを見つけることもできなくはないのですが、些細に思えることだったり、時間に流されてしまったり、なんとなく話題にあげづらい、みたいなことはよくあります。その点、作品という固定の題材が対象ならば問題はありません。先入観やステレオタイプをテーマとした作品によって、違いを認識するきっかけをつくり、本題であるコミュニケーションへ繋げる、というのは実に見事な流れです。
実際に、作品を題材にして他の方と感想の共有や考えたことについて話をしてみて感じたのは、先入観やステレオタイプは、コミュニケーションを阻害するだけでなく、コミュニケーション不足によってできた相手への誤解や思い込みといった隙間にするりと滑り込んで居座るということです。そして最初は小さかった隙間を気づかないうちに広げていって、やがてどうしようもない溝を作り出します。話さずにわかることは格好良いかもしれません。話さずにわかってもらえることは嬉しいかもしれません。それでも、違いを尊重し、話してわかり合うことの素晴らしさをもっと感じられるようになったらいいと思う、そんな体験でした。
ところで「尊重する」という言葉で思い出しましたが、Pay(払う)という動詞はお金に対しても使いますが、尊敬に対しても使いますよね。日本語では「敬意を払う」といい、英語では "pay respect to~"
といいます。直訳でも意味が通じるというのが面白いところです。 "Don't Pay for Me"
、きっと狙ってこのタイトルなのでしょう。ふとしたことで、コンテクストの端と端がつながっていくような丁寧な作り込みで、本当に素敵だと思います。
この展示の全ての作品が、リソグラフという手法で描かれていることもまた、そういった丁寧さを感じる魅力の一つです。リソグラフ印刷では、オフセット印刷のように一度にたくさんの色を出力するのではなく、版画のように色を重ねることで多彩な色彩を表現していきます。思い通りの色を出すためには、何度も試行錯誤を重ねなければならないですし、複数回の印刷の過程で位置が微妙にずれたりします。一筋縄でいかない上にズレるし難しい...どこか人と人の関係を思わせるこの手法にとって、そのあり方こそが魅力であるというのは、なんだか報われるような気持ちになりました。
最後になりましたが、 Don't Pay for Me に出展されているアーティストの皆様、運営の皆様、素敵な展示をありがとうございます。
こちらの展示は、9/12まで渋谷のFabCafe Tokyoでやっているので、興味がわいたらぜひ一度足を運んでみてください。もしできれば誰かと連れ立って、展示から感じたこと考えたことを、お互いに共有しあってみてください。きっと、同じこと違うこと、知っていること知らないこと、わかっているようでわかってなかったこと、いくつもの発見があるはずです。
新卒入社したリクルートを退職しました
2020年2月末日付けで、新卒で入社したリクルートを退職しました。2016年の4月に入社したのでほぼ4年間いたことになります。遅ればせながら、退職エントリというやつを初めて書いております。在籍中は本当に多くの方々にお世話になりました。まずはじめに4年の間に関わり一緒に仕事をさせていただいた方々に改めてお礼を申し上げます。ありがとうございました。
さて、このエントリを書くにあたって、エモ100%のポエムにするというのも考えたのですが、そういうキャラでもないので真面目に書くことにします。 書いているうちに熱が入って結構エモくなってしまいました。
内容はオーソドックスに
- なぜリクルートに入ったか
- どんな仕事をしていたか
- 4年間で変わったこと
- これから何するの
という感じです。
なぜリクルートに入ったか
リクルートとの初めての接点は、大学院M1の冬にふらっと参加したインターンでした。 SFCという少し変わった環境で学部の頃から好きなことしかしてこなかったので、そろそろ外の世界を見ておかないとマズイのでは...という理由のない危機感に背中を押され、『インターン、エンジニア、報酬あり』というなんとも雑な条件でGoogle先生に尋ねて、一番上に出てきたのがリクルートのインターン募集サイトでした。僕はTwitter耳年増だったので「学生エンジニアは搾取される立場にある」という認識が当時からあり、少なくとも報酬を出す会社というのがインターン先を探す一つの指標になっていました。いま思い返しても、正しい指標だったと思います。労働には対価を。当たり前のことです。学生の身であるからこそ、当たり前のことを当たり前にできる会社で働きたかったのです。
いざ参加してみると、思った以上にキャラが濃い人たちが同期に揃っていて、すごく楽しかったのを覚えています。いい意味で鼻っ柱をおられたというか、自分がいかにエンジニアとしてまだまだ学ぶことが多いかということを自覚させられました。その後、たまたまリクルートテクノロジーズでOJT的に学生バイトをやらせてもらうことになり、2ヶ月ほど機械学習とか統計とかを仕込んでもらったりしました。この時点でだいぶリクルートのことが好きになっていて、思い浮かぶ進路はD進かリクルートに就職か、という状態になっていました。
そうこうしているうちに縁あって新卒の選考も通り、最後まで迷ったものの、未来が予想できない方ということでリクルートへの就職を選びました。SFCでの教育の賜物なのですが、考え抜いた末に迷ったら、どうなるか予想できない方を選ぶと決めています。カオスに飛び込む、というやつです。たぶんその方が面白くなるので。
どんな仕事をしていたか
入社してすぐは、仕事がありませんでした。たしかにカオスを望んだのは僕ですが、これはさすがに予想を上回っていました。アサインされるはずだった開発プロジェクトが吹き飛んだ結果、入社早々社内ニート確定という珍事。新卒に向かって「仕事ないんだけど、何やりたい?」は相当ロックだったと思います。とりあえず大笑いして、入社してよかったと思いました。
もともとタスクを割り振られて何かするよりは、自分で課題を見つけて提案する方が好きだったので、これ幸いと自分でできそうなことを探し始めました。僕が配属されていたのは、アルバイトや中途などを対象とした求人サービスを扱う部門でした。サービスのシステムは、かなりレガシーかつ大規模だったので、おいそれと新卒の若造がコアな部分に触れるようなものではありませんでした。
それならば、比較的ライトに試せるWebのフロントエンドで、まだやっていないことをやれないかと模索しはじめ、ユーザの行動データを使ってUXを改善する試みなどを起案したりしました。起案するときにプロトタイプをさくっと作って見せていたのですが、その甲斐あってか当時の上司が面白がってくれて、実際のサービスで試してみることになりました。そのうちに一定の効果がありそうな施策があったりして、既存の開発チームとは別に遊撃部隊として座組みを作ってもらうことになりました。
また一方で、2年目の半ばくらいからは、社内の強いエンジニアの先輩のもとでバックエンドの開発案件にもアサインしてもらいちゃんとしたシステム
の作り方をみっちり仕込んでもらいました。今思い返してみても、かなり恵まれた環境で仕事をしていたと思います。好き勝手させてもらう一方で、基礎となる考え方や経験を仕込んでもらっていたのですから、至れり尽くせりとはこのことです。
そのうちに「Web周りの改善やってる人」みたいな認識をもらいはじめ、レガシーなWebフロントエンドの表示速度改善をする案件もやりました。これはCODEZINEさんで記事にしていただきました。
いろいろな開発案件に取り組んでいるうちに興味がうつっていき、組織としてパフォーマンスを出すために、どのような技術的アプローチができるかということを考えるようになっていました。制約条件が多い中での開発において、最もネックになっているのが組織構造や組織間の力学の違いであるように見えたのです。優秀な人が多いのに、それほどパフォーマンスがでないのはなぜか。その原因を取り除けば、もっとプロダクト開発を加速させられるのではないか。そんなことを思って、データサイエンティストとエンジニアが連携してプロダクト開発できるように、機械学習案件用のAPI基盤を作って検証させてもらったりもしました(障害起こしてすみませんでした)。
最後の一年弱は、運良く社内新規事業案件にアサインしてもらって、社内選りすぐりのプロフェッショナルたちと一緒に仕事していました。これほどに技術レベルが高い人たちばかりに囲まれて仕事するのは初めてだったので楽しくて仕方がありませんでした。また、それまで既存事業の改善一筋で、新規事業として新しい価値を模索する経験はしていなかったので目新しいというのもありました。ただ、一方で違和感も感じていました。まず新規事業とはいえ、社内のプロジェクトなので、大企業の力学に囚われる、ということについてです。既存事業に比べればしがらみは少ないものの、やはり意思決定の自由度とスピードがネックに見えました。また、当然のことながら事業としての新規性や価値が企業の既存アセットとシナジーを生まなければなりません。これは、既存アセットのリソースを優先的に利用できるという利点と背中合わせではありますが、そもそも既存アセットの有用性に強く依存するリスクがあること、また事業としてのポジショニングが難しいということは間違いありませんでした。そして、もう一つの違和感はおそらく温度感だったと思います。メンバーは間違いなく優秀でした。ビジネスサイドも、開発サイドも、いい人が揃っていたと思います。ただその一方で、熱量は足りていなかったように思います。それは僕もです。良くも悪くも社内新規事業なので、ポシャったとして、明日飯が食えないかもしれない、とはならないわけです。そのどこか他人事のような安心感が、少なからずあったように思います。僕のリクルートでの最後の仕事は、とある新規事業を看取るおくりびとでした。
4年間で変わったこと
この4年間で変わったのは、一言でいえば「良いシステム」というものの捉え方です。
学生時代はひたすら研究をしていたので、この頃はシステムは新たなアイデアを実装するための道具に過ぎませんでした。良いシステムとは、必要十分にアイデアを表現し動いているもののことでした。
社会人になって、システムの生む価値の方向性を意識しはじめ、誰のためのシステムか、ということを考えるようになりました。具体的には、技術的なアプローチで、実際のユーザにより良い体験を届けたいということ、またビジネスに貢献したいということを考えはじめました。良いシステムとは、期待した価値を誰かに届ける手段でした。
そして、組織のパフォーマンスなどに目が向きはじめたあたりからは、人間の組織とそれを活かすための仕組みという意味で、システムのことを考えるようになりました。結局のところ、システムは人間と共存できなければいけません。良いシステムとは、という問いに対する今の僕の答えは「人間の営みに即した仕組みのこと」です。人の行動が変われば、システムもまた変わる必要があります。それはビジネスフェーズであったり、プロダクトの性質であったり、中の人のスキルレベルであったり、はたまた政治的な理由によるかもしれません。とはいえ、人の行動には目的があります。正しい目的を設定することができれば、自ずとそれを達成するための行動は決まってきます。良いシステムは、その行動を促し、助け、ときに戒める仕組みです。また、時間軸上のライフサイクルを意識するならば、徐々に移り変わる目的とそれに付随する行動の変化への対応も必要です。
この4年間で「良いシステム」を作りたい、という気持ちは変わっていません。ただ、いまは、人間の営みに寄り添い続ける仕組みを作っていきたいと考えています。
これから何するの
3月からは、リクルートの同期が立ち上げた Boulderというプロダクト検証フェーズのベンチャーでVPoEとしてエンジニアリングのリードと開発体制づくりをやっています。動きが激しいフェーズにおいて、急速なプロダクトの進化を支えるシステムと強い開発チームを作るべく日々楽しく働いています。詳細についてはまだ1文字も書いてない入社エントリで書く予定です。許して。
結びに
僕個人として、新卒でリクルートに入ったことはとても良かったと思っています。
就職先を考えている前途有望な学生や、転職を考えている優秀な方に出会った時は、必ず勧めてみるようにしています。いろいろ思い通りにならなかったり大変なことはありましたが、一度入ってみるのは間違いなく面白いと自信を持って言えます。それほどに優秀な人材が揃っていますし、様々なチャレンジや学びの機会がゴロゴロ転がっています。
『お前はどうしたいの』という有名な語録ネタがありますが、この問いは自分にむけてこそ価値があります(決してマウンティング用の便利フレーズではありません)。なんでもできる会社だからこそ、なぜ、何をしたいのか、自分がどうなりたいのかは常に考えていました。正直これから先のことは今まで以上にわかりませんが、この習慣はきっとこれからも僕を助けてくれるはずです。
別れの言葉を考えていましたが、きっとさようならではないですね。出戻り大歓迎の文化だから、何かの拍子に気付いたらまた中の人になっているかもしれません。その未来がくるかはわかりませんが、社会人としての原点が、自然とそう思える場所だということは、かけがえのない財産だと思っています。
ありがとうリクルート。
またいつか、まだここにない出会いがあれば。
年の瀬だし今年1年どんなスタンプを使ったのか見てみる
これは、Recruit Engineers Advent Calendar 2019 22日目の記事です。
こんにちは。リクルートテクノロジーズの加藤です。 リクルートテクノロジーズのslackはtimesと呼ばれる分報文化が盛んで、ユーザそれぞれが自分のtimesを作って好き勝手呟いたり誰かと雑談したり、真面目に議論したりと、おもいおもいの使い方をしています。
そろそろ年の瀬なので、今年1年timesで使われたスタンプを集計したりしてみようかなと思い立ち、やってみましたという記事です。ソースは全て公開しているので、よかったら遊んでみてください。
出力イメージ
bot宛にメンションを飛ばすと、集計をして返してくれるというシンプルな作りになっています。
下画像は僕のtimesで実行してみた結果です。草
が多いことからどんなtimesなのかがよくわかります。
遊び方
1. slackアプリケーションを作る
まず、ワークスペースに新しくアプリケーションを追加します。 アプリケーションが追加できたら、必要な権限などの設定をしていきます。
botユーザを追加
oauth権限を設定
データを取得するために必要な history
系の権限と、メッセージ投稿に必要な権限を設定します。bot
権限は、botユーザを追加した時に自動で設定されます。
eventサブスクリプションを設定
botあてのメンションに反応するため、app_mention
イベントを設定します。
botユーザをチャンネルに招待する
メンションを飛ばすなりすれば招待できます。app_mention
イベントに反応するために必要です。
2. ローカルで動かしてみる
$ git clone https://github.com/YoshiyukiKato/slack-reaction-counter
$ cd slack-reaction-counter
$ npm install
設定ファイルを作成
サンプルをコピーして、ローカル用の設定ファイルを作成します。 1で作成したslackアプリケーション設定画面から値を取得して、環境変数に設定します。
$ cp local.example.env local.env
export SLACK_SIGNING_SECRET= export SLACK_ACCESS_TOKEN=
エンドポイントを公開
slackのeventを受け取るには、slackからのwebhook用のエンドポイントが必要です。 エンドポイントはグローバルに公開されていないといけないので、ローカルで動かすならngrokを使います。
$ npm run local
$ ngrok http 3000
ngrokで割り当てられたURLをslackアプリケーションのevent subscription URLとして設定します。
3. リモートにデプロイする
僕はappengine上で動かしていますが、herokuでもなんでも動かしたい環境にデプロイしてください。 やることは一つだけで、デプロイが終わったらslackアプリケーションのevent subscription URLを更新するだけです。
さいごに
楽しんでいただければ幸いです。もしバグとか見つけたらIssueなど上げてくださると助かります。
Node.jsでサクッとGRPCを使うためのライブラリgrpc-kitをつくりました
この記事は、Recruit Engineers Advent Calendar 2018 4日目の代打記事です。
こんにちは。リクルートでエンジニアをやっている加藤です。 アドベントカレンダーの穴が寂しかったので埋め記事投稿です。つい先日、dev.toに投稿した元記事の和訳版記事になります。村上春樹にでもなった気分です。
タイトルの通りこの記事では、Node.jsでGRPCを簡単に使うためのライブラリを作ったので、そのご紹介をしたいと思います。
GRPCのアプリケーションをNode.jsで作るときには、grpc
と @grpc/proto-loader
というライブラリを使います。
この子達を使うとサクッとGRPCのサーバ/クライアントを作ることができてとても有難いのですが、いかんせんAPIがプリミティブなので個人的に使いづらさを感じていました。もっとこう、createClient
とかcreateServer
とかでインスタンス作って、use
みたいのでミドルウェアっぽく設定追加して、という感じで使いたい欲求がありました。
そんなわけで、grpc
と@grpc/proto-loader
をラップしたgrpc-kitというライブラリをつくりました。jsペライチ100行未満の超お手軽ライブラリです。以下のような感じで使います。
greeter.proto
syntax="proto3"; package greeter; service Greeter { rpc Hello (RequestGreet) returns (ResponseGreet) {} rpc Goodbye (RequestGreet) returns (ResponseGreet) {} } message RequestGreet { string name = 1; } message ResponseGreet { string message = 1; }
server.js
const {createServer} = require("grpc-kit"); const server = createServer(); server.use({ protoPath: "/path/to/greeter.proto", packageName: "greeter", serviceName: "Greeter", routes: { hello: (call, callback) => { callback(null, { message: `Hello, ${call.request.name}` }); }, goodbye: async (call) => { return { message: `Goodbye, ${call.request.name}` }; } } }); server.listen("0.0.0.0:50051");
createServer
は grpc.Server
をラップしたクラスのインスタンスを返します。このインスタンスは use
メソッドを提供していて、greeter.proto
へのパス、パッケージ名、サービス名、それからgreeter.proto
で定義された各メソッド(hello
, goodbye
)のハンドラを渡すことができます。ハンドラには、asyncな子も、asyncじゃない子も渡せるようにしてあります。これで設定は完了なので、あとはlisten
というお里が知れそうな名前のメソッドにアドレスを渡してサーバを起動します。
client.js
//client.js const {createClient} = require("grpc-kit"); const client = createClient({ protoPath: "/path/to/greeter.proto", packageName: "greeter", serviceName: "Greeter" }, "0.0.0.0:50051"); client.hello({ name: "Jack" }, (err, response) => { if(err) throw err; console.log(response.message); }); client.goodbye({ name: "John" }, (err, response) => { if(err) throw err; console.log(response.message); });
createClient
は grpc.Client
のインスタンスをそのまま返します。これはもう処理をまとめて僕が好きな形にしただけです。
さらに詳しい使い方については、 リポジトリ のREADMEと、あとexampleにサンプルコードを入れてあるのでご参照ください。 この記事が何かのお役に立てば幸いです。
Google Kubernetes EngineにNAT付きでConcourse CIをたてる
(この記事は、Recruit Engineers Advent Calendar 2018 16日目の記事です)
こんにちは。リクルートでエンジニアをしている加藤です。 フロントエンドをやったり、バックエンドをやったり、プロダクティビティ的なことをやったりと、いろんなことをやっています。最近は、KubernetesとGCPを触る機会が増えてきたのと、あとJenkinsがもういい加減辛くなってきてConcourse CIを触り始めました。つまりこの記事は、 最近やったこと全部盛り な内容になっております。すこし長いですがお付き合いください。
この記事でやること
この記事では、GKE(Google Kubernetes Engine)に、NAT付きでConcourseを立てる方法をご紹介します。今回想定している状況は、
- ファイヤウォールの内側にいる、プライベートのサービス(GitlabやGithubEnterperiseなど)につなぎに行きたい
- Concourseには特定のIPからのみ接続を許可したい
- Concourseへの接続はHTTPSにしたい
というものです。エンタープライズの開発環境では、よくある状況かと思います。 全体構成は以下のようになります。
この構成を作るため、以下の順で進めていきます。
- NAT Gateway付きのGKEクラスタを作る
- Let's EncryptのTLS証明書をGKEクラスタで管理する
- ConcourseをGKEクラスタ上で動かす
- Cloud Armorで接続元IPを制限する
この記事で例示されるコードは、後ほどリポジトリにアップして、記事に追記します。
Concourse CI?
Concourse CIは、pivotalによって開発されている、オープンソースのCIツールです。ググるとJenkins vs Concourseみたいな記事が出るくらいには人気があります。特徴的な点としては、パイプラインの状態可視化と、設定ファイルによる明示的なタスク定義があります。ConcourseCIについては、数ある紹介記事・比較記事にお任せします。個人的にはMediumにある公式の紹介記事が丁寧に書いてあっておすすめです。
参考 - JenkinsとConcourse CIを比較 - Concourse official articles on Medium
0. 前提
⚠️ これ以降の手順は、以下の項目を前提として進みます。ご注意ください ⚠️
- GCPプロジェクトを持っていること
- ローカルマシンにGoogle Cloud SDKがインストールされていて、
gcloud
コマンドが利用可能であること gcloud
コマンドでログインしていて、GCPプロジェクトを設定していること- ローカルマシンにkubectlがインストールされていて、
kubectl
コマンドが利用可能であること
1. NAT Gateway付きのGKEクラスタを作る
GKEクラスタからのリクエストの送信元IPを固定するには、NAT Gatewayが必要です。今回、NAT Gatewayの役割を果たしてくれるのは、GCE(Google Compute Engine)のVMインスタンスです。このVMインスタンスをNATインスタンス
と呼びます。GKEクラスタのアウトバウンドのトラフィックは、全てNATインスタンスを経由するようにします。これによって、GKEクラスタからのリクエストの送信元IPは、NATインスタンスのものになります。プライベートサービスのファイヤウォールには、NATインスタンスのIPを許可する設定を追加してあげれば、GKEクラスタからの接続を許可することができます。
本章では、リソースのデプロイにCloud Deployment Managerを利用します。各リソース定義のフォーマットは、yamlをベースとしてjinja2で書かれています。サポートされているリソース定義については、Cloud Deployment Managerドキュメントのサポートされるリソースタイプから全て辿ることができます。
1.1. ネットワークリソースの定義
ネットワークリソースを定義します。必要なのは、以下の3つです。
構成のベースとなるVPCネットワークは、構成全体を囲むいわゆるグループのようなものです。network
というリソースで表現されます。GKEクラスタのサブネットと、NATインスタンスのサブネットは、ネットワークに属するグループです。subnetwork
というリソースで表現されます。
resources: ######## Network ############ - name: devops-nat-network type: compute.v1.network properties: autoCreateSubnetworks: false ######### Subnets ########## ######### For Cluster ######### - name: devops-subnet type: compute.v1.subnetwork properties: network: $(ref.devops-nat-network.selfLink) ipCidrRange: 172.16.0.0/12 region: asia-northeast1 ########## For NAT Instance ########## - name: devops-nat-subnet type: compute.v1.subnetwork properties: network: $(ref.devops-nat-network.selfLink) ipCidrRange: 10.1.1.0/24 region: asia-northeast1
GCPでは、ネットワークはCIDRとリージョンを持たず、サブネットがCIDRとリージョンを持っています。同じネットワークに属するサブネット同士は、CIDRの範囲が被ってはいけないので注意してください。この辺りは少し混乱するかもしれませんが、一旦はグルーピングがしたいんだな、くらいの理解で大丈夫です。さらに詳しくはVirtual Private Cloud(VPC)ネットワークの概要を読んでください。AWSと比較して違いが知りたいという方は【AWSしかやったことない人向け】AWSとGCPのネットワークの違いを理解してみようが非常に丁寧でおすすめです。
この設定で、以下のように枠だけの状態ができました。
各リソースのname
は適当につけました。今回はConcourseのための構成なので、全てにdevops
というprefixをつけています。後からどんな用途のリソースかわかればいいと思いますので、状況に応じて好きなものをつけてください。
1.2. NATインスタンスとGKEクラスタの定義
########## NAT Instance ########## - name: devops-nat-vm type: compute.v1.instance properties: zone: asia-northeast1-a canIpForward: true tags: items: - nat-to-internet machineType: https://www.googleapis.com/compute/v1/projects/{{ env["project"] }}/zones/asia-northeast1-a/machineTypes/f1-micro disks: - deviceName: boot type: PERSISTENT boot: true autoDelete: true initializeParams: sourceImage: https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-9-stretch-v20181113 networkInterfaces: - network: projects/{{ env["project"] }}/global/networks/devops-nat-network subnetwork: $(ref.devops-nat-subnet.selfLink) accessConfigs: - name: External NAT type: ONE_TO_ONE_NAT ##asia-northeast1リージョンに外部IPアドレスを予約してから入れる natIP: metadata: items: - key: startup-script value: | #!/bin/sh # -- # --------------------------- # Install TCP DUMP # Start nat; start dump # --------------------------- apt-get update apt-get install -y tcpdump apt-get install -y tcpick iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE nohup tcpdump -e -l -i eth0 -w /tmp/nat.pcap & nohup tcpdump -e -l -i eth0 > /tmp/nat.txt & echo 1 | tee /proc/sys/net/ipv4/ip_forward ########## FIREWALL RULES FOR NAT Instance ########## ## アウトバウンドトラフィック - name: devops-nat-vm-firewall type: compute.v1.firewall properties: allowed: - IPProtocol : tcp - IPProtocol : udp - IPProtocol : icmp - IPProtocol : esp - IPProtocol : ah - IPProtocol : sctp sourceTags: - route-through-nat network: $(ref.devops-nat-network.selfLink) ## インバウンドトラフィック - name: devops-nat-vm-ssh type: compute.v1.firewall properties: allowed: - IPProtocol : tcp ports: [22] sourceRanges: ## デバッグのため、特定のネットワーク内からのみNATへのSSHを許可 - YYY.YYY.YYY.YYY/ZZ network: $(ref.devops-nat-network.selfLink)
########## GKE CLUSTER CREATION ########## - name: devops type: container.v1.cluster metadata: dependsOn: - devops-nat-network - devops-subnet properties: cluster: name: devops network: devops-nat-network subnetwork: devops-subnet nodePools: - name: default-pool initialNodeCount: 1 config: tags: - route-through-nat # マシンタイプについてはhttps://cloud.google.com/compute/docs/machine-types?hl=ja machineType: n1-highmem-2 imageType: ubuntu autoscaling: enabled: true minNodeCount: 1 maxNodeCount: 3 zone: asia-northeast1-a
この設定で、以下のように枠に箱が入った状態ができました。
1.3. ネットワークルーティングの定義
########## GKE MASTER ROUTE ########## - name: devops-master-route type: compute.v1.route properties: destRange: $(ref.devops.endpoint) network: $(ref.devops-nat-network.selfLink) nextHopGateway: projects/{{ env["project"] }}/global/gateways/default-internet-gateway priority: 100 tags: - route-through-nat ########## NAT ROUTE ########## - name: devops-route-through-nat metadata: dependsOn: - devops - devops-nat-network type: compute.v1.route properties: network: $(ref.devops-nat-network.selfLink) destRange: 0.0.0.0/0 description: "route all other traffic through nat" nextHopInstance: $(ref.devops-nat-vm.selfLink) tags: - route-through-nat priority: 800
この設定で、以下のように箱の間に道を通すことができました。
1.4. 静的IPアドレスを取得する
静的なIPアドレスを取得します。GCEのVMにデフォルトで割り振られるIPアドレスは動的なもので、インスタンスを再起動したりすると切り替わってしまいます。NATインスタンスの場合、これではあまり嬉しくありません。
静的なIPアドレスを取得する詳しい方法は公式のドキュメントを参照してください。アドレスを取得する際には、先ほど定義したGKEクラスタと同じリージョンを選択します。静的なIPアドレスが取得できたら、1.2
で空欄にしていた、NATインスタンス設定のnatIP
に追記します。
取得したIPを許可するよう、プライベートのサービスのファイヤウォールに設定します。これで、クラスタからプライベートのサービスに繋がるようになりました。
1.5. 設定をデプロイする
ここまでで、基本的な構成の設定が完了しました。あとは、これをデプロイするだけです。デプロイには、gcloud
コマンドを使います。cluster-with-nat-route.yaml
というファイルに上記の設定がひとまとめにされていて、このデプロイにdevops-with-nat
という名前をつける場合、以下のようなコマンドになります。
$ gcloud deployment-manager deployments create devops-with-nat --config cluster-with-nat-route.yaml
処理には少し時間がかかります。処理が完了したらgcloud
コマンドで、ローカルマシンのkubectl
をGKEクラスタに繋げます。
$ gcloud container clusters devops get-credentials
1.6. Helmをインストールする
この章の仕上げとして、GKEクラスタでHelmが使えるようにセットアップします。 Helmは、Kubernetes用のパッケージマネージャです。これ以降の2章、3章では、GKEクラスタへのデプロイに、Helmを利用します。
まず、ローカルマシンにHelmクライアントをインストールします。手順はリンク先を参照してください。完了すると、helm
コマンドが使えるようになります。
GKEクラスタでHelmを利用するには、適切な権限が付与されたサービスアカウントが必要です。Helmのデフォルト設定に従い、tiller
という名前でサービスアカウントを作成します。
apiVersion: v1 kind: ServiceAccount metadata: name: tiller namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: tiller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: tiller namespace: kube-system
上記設定がhelm.yaml
という名前の場合、GKEクラスタへの適用は次のように行います。
$ kubectl apply -f helm.yaml
サービスアカウントが作成できたら、ローカルマシンのhelm
コマンドを初期化します。
$ helm init --upgrade --service-account tiller
2. Let's encryptのTLS証明書をGKEクラスタで管理する
GKEクラスタができたので、TLS証明書の準備に移ります。TLS証明書は、Let's Encryptで取得します。GKEクラスタで証明書管理を行う場合、cert-manager という超便利ツールを使います。
2.1. cert-managerをインストールする
cert-managerは、すでにhelmのパッケージが公開されており、コマンド一つでデプロイすることができます。今回は、cert-manager用に新しくnamespaceを切ります。
$ kubectl apply -f k8s/namespace.yaml $ helm install --name cert-manager --namespace cert-manager stable/cert-manager
2.2. Let's EncryptへTLS証明書作成依頼を発行する
今回、ドメインはAWSのRoute53で取得しているという想定です。その他のドメインプロバイダの場合、Issuer
のspec.acme.dns01
の書き方が変わります。dns01でのチャレンジに使えるドメインプロバイダと設定の書き方は、cert-managerのドキュメントに書いてあります。
apiVersion: v1 kind: Secret metadata: name: prod-route53-credentials-secret namespace: cert-manager type: Opaque data: secret-access-key: YOUR_AWS_SECRET_ACCESS_KEY(base64 encoded) --- apiVersion: certmanager.k8s.io/v1alpha1 kind: Issuer metadata: name: letsencrypt-prod namespace: cert-manager spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: your_email_here@example.com privateKeySecretRef: name: letsencrypt-prod dns01: providers: - name: prod-dns route53: region: ap-northeast-1 accessKeyID: YOUR_AWS_ACCESS_KEY_ID secretAccessKeySecretRef: name: prod-route53-credentials-secret key: secret-access-key --- apiVersion: certmanager.k8s.io/v1alpha1 kind: Certificate metadata: name: mycert namespace: cert-manager spec: secretName: mydomain-net-tls issuerRef: name: letsencrypt-prod commonName: '*.mydomain.net' acme: config: - dns01: provider: prod-dns domains: - '*.mydomain.net'
上記設定がcert.yaml
という名前の場合、GKEクラスタへの適用は次のように行います。
$ kubectl apply -f cert.yaml
証明書の発行には少し時間がかかります。申請状況の経過は次のコマンドで確認できます。
$ kubectl describe cert mycert -n cert-manager
Failed等の表示が途中でみられるかもしれませんが焦らず待ってみてください。完了するとmydomain-net-tls
というSecretが作成されます。作成されたかどうかは、以下のコマンドで確認できます。
$ kubectl get secret -n cert-manager
2.3. namespaceを跨いでワイルドカード証明書を使い回す
ワイルドカード証明書を、クラスタ内のnamespaceを跨いで使いまわしたい、というのは非常にわかりやすい要求です。Let's EncryptのAPIコールには件数制限があるということと、namespaceごとに証明書を取る手間を考えると、誰もがそうしたいと思うでしょう。しかし、cert-managerで取得した証明書をnamespaceを跨いで使うには、少し工夫が必要です。
cert-managerにはClusterIssuer
というのがあり、これを使うとクラスタ内の異なるnamespaceで証明書を使いまわせそうに見えるのですが、悲しいことにそうはいきません。このIssueにもある通り、ClusterIssuer
自体は使いまわせても、取得した証明書は使いまわせないという悲しい仕様になっています。
そこで、kubedを使います。一度Issuer
で取得した証明書の変更を監視しておいて、対象となるnamespaceに都度連携する方式です。
kubedは、helmでインストールすることができます。
$ helm repo add appscode https://charts.appscode.com/stable/ $ helm install appscode/kubed --name kubed --namespace kube-system \ --set apiserver.enabled=false \ --set config.clusterName=devops
kubedのインストールが完了したら、先ほど作成されたmydomain-net-tls
に、kubedが監視するためのアノテーションを貼ります。
$ kubectl annotate secret mydomain-net-tls -n cert-manager kubed.appscode.com/sync="app=kubed"
この章の仕上げとして、Concourseをデプロイするnamespace を作り、そこにkubedで証明書を連携します。
apiVersion: v1 kind: Namespace metadata: name: concourse labels: app: kubed
kubedが連携先として認識するため、labelにapp=kubed
を設定しています。kubectlで設定を反映します。
$ kubectl apply -f concourse-namespace.yaml
証明書が連携されているかどうか確認して完了です。
$ kubectl get secret mydomain-net-tls -n concourse
ここまでで、構成は以下のようになっています。だいぶできてきました。
3. ConcourseをGKEクラスタにデプロイする
3.1. 静的なIPアドレスを取得してドメインに紐づける
Concourse用に静的なIPアドレスを取得します。1.4.
の手順と同じ方法で取得し、concourse
という名前をつけます。この名前はConcourseの設定で使います。取得したIPアドレスを、AWS Route53でドメインに紐づけます。今回は、concourse.mydomain.net
という名前を紐づけた想定で進めます。
3.2. ソースをfetchして設定を書く
Helmで提供されているConcourseのパッケージに、設定を追加してデプロイします。まずソースをfetchしてきます。
$ helm fetch --untar stable/concourse
新しくconcourse
というディレクトリが作られます。この中にある、values.yaml
がデフォルトの設定ファイルになります。コピーして持ってきましょう。
$ cp ./concourse/values.yaml ./myvalues.yaml
この中に、変更する箇所がいくつかあります。設定ファイル全体をここで見るのは長すぎるので、ピックアップして見ていきます。設定ファイルには大きく分けてconcourse
という項目と、web
という項目があります。concourse
にはアプリケーション内の設定を書き、web
にはkubernetesリソース周りの設定を書くようになっています。
concourse: web: logLevel: error bindPort: 8080 # IPを紐づけたドメイン externalUrl: https://concourse.mydomain.net tsa: logLevel: info bindPort: 2222 peerIp: #ここはあとで追加する
web: service: type: NodePort ingress: enabled: true annotations: #取得した静的IPの名前 kubernetes.io/ingress.global-static-ip-name: concourse hosts: #IPを紐づけたドメイン - concourse.mydomain.net tls: #cert-managerで取得してkubedで連携した証明書 - secretName: mydomain-net-tls #IPを紐づけたドメイン hosts: - concourse.mydomain.net
3.2. デプロイして設定をアップデートする
$ helm install --name concourse --namespace concourse -f concourse.yaml ./concourse
concourseのworkerはwebのpeerIp
がないとエラーを吐き続けるのですが、これはデプロイ後でないとわかりません。
$ kubectl get svc concourse-web -n concourse
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE concourse-web NodePort XXX.XXX.XXX.XXX <none> 8080:30979/TCP,2222:31674/TCP 18s
のXXX.XXX.XXX.XXX
を、myvalues.yaml
のpeerIp
に設定して再度デプロイします
$ helm upgrade -f myvalues.yaml concourse ./concourse
ここまでで、以下のような状態まできました。あと一息です。
3.3. 動作確認
Concourse自体はすぐに立ち上がるのですが、LBが立ち上がるまで少し時間がかかります。GCPのコンソール上で状態を確認しつつ、全てのリソースが立ち上がったら、接続できるかどうか確認します。
今回、ユーザ名とパスワードは変更していないので、デフォルト設定のままです。ユーザ名:test
、パスワード:test
でログインしてみましょう。
webから
https://concourse.mydomain.net
にアクセスして、右上にあるlogin
ボタンからフォームを開きます。
flyから
Concourseでは、fly
というCLIを使って設定の操作を行います。ローカルマシンにflyをインストールして、以下のコマンドでログインします。
$ fly -t myci login -c https://concourse.mydomain.net -u test -p test
4. Cloud Armorで接続元IPを制限する
最後に、Cloud Armorを使って、接続元のIPを制限します。Cloud Armorは現在Beta版として提供されているセキュリティサービスです。LBに組み込むことで、GCP上のリソースをDDoS攻撃から守ってくれる他、ファイヤウォールの設定を書くこともできます。本来、kubernetesのnetwork policyを書くのが王道だと思いますが、今後設定を使いまわしたいというのと、あと単純に使ってみたかったという理由なので許してください。
設定は、GCPのコンソール上から行うことができます。メニューから、ネットワークセキュリティ > Cloud Armor
を選択します。
ポリシーの作成
ボタンを押すと、設定編集画面が開きます。デフォルトアクションを拒否
にして、許可ルールを追加していきます。ターゲットへのポリシーの適用
で、先ほど作られたLBを選択したら完了です。
実際に、許可されたアドレス外からアクセスしようとすると、403 Forbidden
が表示されるので試してみてください。
さて、ここまでで全ての構成が完成しました! 長かった...。お付き合いいただきありがとうございました。
まとめ
この記事では、エンタープライズの開発環境によくある状況を想定して、GKEにConcourse CIを立てる方法をご紹介しました。GCPのネットワーク設定や、cert-managerとkubedの合わせ技による証明書の管理などは、かなりややこしい部分だと思います。かなり駆け足になってしまいましたので、随時記述を補足していきたいと思います。
この記事が何かのお役に立てば幸いです。
※残課題※
以下残課題は、対応完了次第追記します。
Lighthouseのバッチ実行と結果レポートをいい感じでやるためのパッケージを作りました
nightharborというパッケージを作りました。対象ページのリストを読み込み、ひたすらlighthouseを実行して、それらの結果をレポーティングためのものです。名前はlighthouse(灯台)が稼働してそうなとこ、という安直な感じでつけました。
lighthouseって???
本題の前に、lighthouseについて軽くお話しします。ご存知の方も多いかとおもいますが、Googleが提供しているサイトパフォーマンス計測ツールです。サイトパフォーマンスをスコア化して表示してくれるだけでなく、読み込むまでにどれくらい時間がかかったのか、ページ速度を遅くしている要因が何なのか、どうすれば改善できるのか、などいろいろ丁寧に教えてくれるステキツールです。Chromeの開発者ツールにある Audits
から使うことができます。ブラウザからの使い方は こちらなどをご覧いただければと思います。
本題
このlighthouseというツールですが、node.js上でも動きます。 今回作ったパッケージは、node.js上でlighthouseをバッチ実行するためのものです。
それなりの規模のWebサイトになってくると、パフォーマンスを調べたいページについて、手動でぽちぽちlighthouseを実行するのは結構な手間です。 加えて、「定期的にモニタリングしたい」とか「競合の計測もしたい」なんて要望もでてきたりしたら大変です。手動実行なんてしたくないですし、結果のファイルをどこかに手動アップロードしまくるなんてのも絶対にやりたくありません。
なので、やりたいこととしては、ざっくり以下のような感じです。
- 好きな場所から対象ページリストを読み込む
- 順番にlighthouseを実行する
- 好きな場所に好きな形式で出力する
1, 3を自由にカスタマイズできて、2は設定(lighthouse, puppeteer)が渡せるように作りました。図にするとこんな感じです。
基本的な使い方
基本的な使い方については、サンプルプロジェクトをcloneして実行していただくのが一番手っ取り早いかと思います。
$ git clone https://github.com/YoshiyukiKato/nightharbor-example.git $ cd nightharbor-example $ npm install $ npm start
https://google.com first-contentful-paint: 0.98 first-meaningful-paint: 0.98 speed-index: 0.99 screenshot-thumbnails: null final-screenshot: null estimated-input-latency: 0.82 time-to-first-byte: 1 first-cpu-idle: 0.87 interactive: 0.88 user-timings: null critical-request-chains: null redirects: 1 mainthread-work-breakdown: 0.75 bootup-time: 0.97 uses-rel-preload: 1 uses-rel-preconnect: 0.74 font-display: 1 network-requests: null metrics: null uses-long-cache-ttl: 1 total-byte-weight: 1 offscreen-images: 1 render-blocking-resources: 1 unminified-css: 1 unminified-javascript: 1 unused-css-rules: 1 uses-webp-images: 1 uses-optimized-images: 1 uses-text-compression: 1 uses-responsive-images: 1 efficient-animated-content: 1 dom-size: 1
こんな感じの実行結果がコンソールに出力されたでしょうか。
nhb.config.js
には、このプロジェクトの全ての設定が書いてあります。
const {SimpleLoader} = require("nightharbor/loader"); const {SimpleReporter} = require("nightharbor/reporter"); module.exports = { loaders: [ new SimpleLoader([ { url: "https://google.com" } ]) ], reporters: [ new SimpleReporter() ], //following params are optional //default params are shown as comment /* chromeNum: 1, puppeteerConfig: { headless: true }, lighthouseConfig: { extends: 'lighthouse:default', settings: { onlyCategories: ['performance'], } } */ }
nightharborでは、CLIからの実行とプログラム上での実行の二つを用意していますが、どちらもこのconfigを渡すだけでOKです。 CLIの場合はconfigファイルへのpathを
$ npm i -g nightharbor $ nhb --config ./path/to/config.js
プログラムからの場合は直接configオブジェクトをexec
メソッドに渡します。
import nhb from "nightharbor"; import config from "./path/to/config"; nhb.exec(config) .then(() => console.log("done")); .catch(console.error);
ここからは、nhb.config.js
の内容について説明をしていきます。
loaders
loaders
は、lighthouse実行対象リストを読み込むLoader
の配列です。SimpleLoader
は、組み込みのもっとも簡単なLoader
で、生の配列でlighthouseの実行対象を指定するためのものです。Loader
が扱う実行対象の情報には、url
というパラメータが含まれている必要があります。
{ "url": "https://google.com" }
いまのところ、組み込みのSimpleLoader
に加えて、僕自身が使うために作ったLoader
は以下の2つです。
loaders
には、Loader
のインタフェースを実装したクラスのインスタンスであれば、含めることができます。以下のような感じで独自のLoader
を作ることもできます。
class CustomLoader { /** * @return {Promise<{ url: string, [key: string]: any }[]>} */ load(){ //some asynchronous fetch tasks such as read file and api request. return Promise.resolve([ { url: "https://google.com" } ]); } }
load
メソッドがあればいいのでサクッと作れます。
なお、ここで読み込む対象ページの情報は、最終的にlighthouseの実行結果と結合されReporter
に渡されます。なので、url
以外にもレポートに含めたい情報を含めておくと便利かもしれません。
reporters
reporters
は、lighthouseの実行結果(audits)を任意の形で出力するReporter
の配列です。SimpleReporter
は、組み込みのもっとも簡単なReporter
で、コンソールにlighthouseの結果を出力します。
いまのところ、組み込みのSimpleReporter
に加えて、僕自身が使うために作ったReporter
は以下の三つです。
- nightharbor-file-reporter
- nightharbor-s3-reporter
- nightharbor-bigquery-reporter
- GCP BigQueryに結果をアップロードする
reporters
には、Reporter
のインタフェースを実装したクラスのインスタンスであれば、含めることができます。独自のReporter
を作ることもできます。
class CustomReporter{ /** * will be called when a lighthouse execution completed * @param {any} result * @return {void} */ write(result){ //do something } /** * will be called after all executions * @return {Promise} */ close(){ //do something } }
Reporter
には、一回のlighthouse実行後に結果が渡されるwrite
メソッドと、全ての対象ページへのlighthouse実行が終了した後に呼ばれるclose
メソッドを実装します。なお、現状write
メソッドに渡ってくる結果情報は、データサイズを抑えるため、各audit(例えば、speed-index
など)ごとscore
のみにしています(auditのインタフェースはこちらを見てください)。details
など他の情報も取りたいという要望ありましたらIssueください
chromeNum
puppeteerで起動するchromeの数です。対象ページが多い場合、一つのchromeで処理するのでは流石に時間がかかるので、何個も立ち上げて同時に処理を走らせることができます。ただし、数字を大きく設定する場合、マシンスペックを十分に確保した上で行う必要があります。
puppeteerConfig
puppeteerの設定です。詳しくはこちらをご覧ください。
lighthouseConfig
lighthouseの設定です。詳しくはこちらをご覧ください。
実際の使い方の例
僕自身は、S3から対象リストのCSVファイルを読み込ませるようにして、CloudWatch + AWS Batchで定期実行し、結果をS3とBigQueryに出力しています。 nightharborのアプリケーションはdocker imageにして、AWS ECRに上げています。
アプリケーションのimageはビルド後のサイズが気になるのでnodeのalpineベースで作ったのですが、lighthouseの公式docに従って進めても動かないという罠があって結構大変でした。AWS上での設定や実際に定期計測してみた話はまた別途記事にまとめようかと思いますが、とりあえずalpineベースのサンプルプロジェクトを作ったので、よかったらご活用ください。
まとめ
lighthouseをバッチ実行していい感じでレポーティングするためのパッケージ、nightharborをご紹介しました。 何かのお役に立てば幸いです。IssueもPRもお待ちしております(日本語でも英語でも大丈夫です)。
ログ収集基盤sentryのオンプレ版をローカルに立てて遊ぶ
アプリケーションログ収集基盤のsentryを触ってみたらすごい便利そうだったので、仕事でも使いたいなーと思ったのですが、ホスティング版をEnterprise向けに大々的に使おうとすると結構お金がかかりそうなので、まずは小さく試せるオンプレ版で使用感をみてみようという試み。 dockerベースでサクッと入れられるのでとても便利です。
手順は↑のREADMEに書いてある通りですが、一応。
0. クローンしてくる
$ git clone https://github.com/getsentry/onpremise.git $ cd onpremise
1. ディレクトリつくる
$ mkdir -p data/{sentry,postgres}
2. シークレットキーを生成してdocker-compose.ymlに貼り付ける
$ docker-compose run --rm web config generate-secret-key
一瞬どこにキーが出力されてるのかわかりづらいですが、一番最後、WARNINGの後に出力されてるのがキーです。
... WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. [このへんにキーが出力されてる]
こいつをコピーして、docker-compose.yml
に貼り付けます
... version: '2' services: base: restart: unless-stopped build: . environment: # Run `docker-compose run web config generate-secret-key` # to get the SENTRY_SECRET_KEY value. SENTRY_SECRET_KEY: [ここにキーを貼り付ける] SENTRY_MEMCACHED_HOST: memcached ...
3. データベースを構築する
$ docker-compose run --rm web upgrade
このときに、初期アカウントも作ります。ダーっとログが出力されたあと、プロンプトが起動するので順番に答えていきます。
Would you like to create a user account now? [Y/n]: Y Email: [自分のメアドを入力] Password: [好きなパスワードを入力] Repeat for confirmation: [パスワード確認] Should this user be a superuser? [y/N]: Y
最後に「superuserにする?」って聞かれるので、Yにしときました。adminはいた方がいいよね。
4. アプリケーションを起動する
$ docker-compose up -d
5. アプリケーションにアクセスする
http://localhost:9000
でアクセスできるようになってます。
さっき設定したアカウントのメアドとパスワードでログインします。
- Root URL: sentryサーバにアクセスするためのURL。ローカルで試すだけなので
http://localhost:9000
にしました。外向きに公開するならば、そのURLを入力します。 - Admin Email: sentryサーバの管理者アドレス。自分のメールアドレスを入れました。
- Allow Registration: 誰でもアカウント作れるようにするかどうか。今回は自分だけですしデフォルトのままオフで。
- Anonymize Beacon: sentryの開発元に送られるデータを匿名化するかどうか。管理者アドレスとかその辺の情報が全部除外されるようです。ただし、セキュリティアップデートとかの連絡はできなくなっちゃうよ、とのこと。実サービス向けでの運用始めたらオフにした方がいいのかもしれないですが、今回はお試しなのでデフォのままオンで。
もろもろ設定してcontinueを押すと、ダッシュボードに遷移します。
超簡単でした。ここまで10分かかってない... せっかくなのでこの土日で遊び倒してみようと思います。