Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
クックパッドでの Webアプリケーション開発 2017 / Web application d...
Search
Kohei Suzuki
November 16, 2017
Technology
20
10k
クックパッドでの Webアプリケーション開発 2017 / Web application development in Cookpad 2017
Rails Developers Meetup #7 東京会場
https://techplay.jp/event/631428
Kohei Suzuki
November 16, 2017
Tweet
Share
More Decks by Kohei Suzuki
See All by Kohei Suzuki
東京Ruby会議12 Ruby と Rust と私 / Tokyo RubyKaigi 12 Ruby, Rust and me
eagletmt
3
850
少人数でも運用できるインフラ作り / Operating infrastructure with less effort
eagletmt
1
3k
Cookpad Lounge #4 SRE 座談会 コンテナ中心の構成からサーバーレスへの展望 / From containers to serverless
eagletmt
0
650
Cookpad Tech Kitchen #20 Amazon ECS の安定運用 / Building a steady ECS infrastructure
eagletmt
1
3k
ECS を利用したデプロイ環境
eagletmt
12
6.7k
ActiveRecord 3.2 -> 4.1
eagletmt
3
1.8k
クックパッドにおける Rubyの活用
eagletmt
0
490
複数DBとRails
eagletmt
14
7k
R/W Splitting in Rails
eagletmt
2
1.5k
Other Decks in Technology
See All in Technology
Goで実践するBFP
hiroyaterui
1
120
EMConf JP の楽しみ方 / How to enjoy EMConf JP
pauli
2
140
.NET 最新アップデート ~ AI とクラウド時代のアプリモダナイゼーション
chack411
0
190
技術に触れたり、顔を出そう
maruto
1
140
コロプラのオンボーディングを採用から語りたい
colopl
5
940
Git scrapingで始める継続的なデータ追跡 / Git Scraping
ohbarye
5
470
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
6
54k
30分でわかるデータ分析者のためのディメンショナルモデリング #datatechjp / 20250120
kazaneya
PRO
22
4.8k
comilioとCloudflare、そして未来へと向けて
oliver_diary
6
430
2025年の挑戦 コーポレートエンジニアの技術広報/techpr5
nishiuma
0
140
商品レコメンドでのexplicit negative feedbackの活用
alpicola
1
330
いま現場PMのあなたが、 経営と向き合うPMになるために 必要なこと、腹をくくること
hiro93n
9
7.2k
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
365
25k
The Cult of Friendly URLs
andyhume
78
6.1k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
113
50k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
127
18k
KATA
mclloyd
29
14k
Building an army of robots
kneath
302
45k
Building Adaptive Systems
keathley
38
2.4k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
The Language of Interfaces
destraynor
155
24k
Being A Developer After 40
akosma
89
590k
Transcript
クックパッドでの Webアプリ ケーション開発 2017 Kohei Suzuki (@eagletmt)
自己紹介 - Kohei Suzuki (@eagletmt) - クックパッド 技術部開発基盤グループ - Docker
を使ってアプリケーションを動かす基盤を全面的に担当
アウトライン - 去年の時点での開発環境 - アプリケーションをデプロイするまでのフロー - Docker、ECS、Hako - 今年に入ってからやってきたこと -
Web アプリケーションの統合管理コンソール - pull-request 単位のステージング環境 - 分散トレーシング - 次にやっていきたいこと
これまでのあらすじ - クックパッドではマイクロサービスを推進してきた - Web API のインターフェイスを決める Garage、GarageClient - 各アプリケーションから共通で使えるツールの整備
- 定期実行ジョブ管理システム Kuroko2 - 非同期ジョブキューシステム Barbeque - エラートラッカーとしては Sentry を採用 - アプリケーションの実行基盤としては Amazon ECS を採用
Web アプリケーションのデプロイフロー
Web アプリケーションのデプロイフロー - GitHub Enterprise - アプリケーションと Dockerfile を書く -
hako_apps という1つのリポジトリに Hako の定義ファイル (YAML) を書く - ビルドパイプライン - Jenkins でテストを実行し docker build して Amazon ECR に docker push - デプロイ実行 - Slack から Ruboty (chatbot) を経由して Rundeck で hako deploy コマンドを実行 - Amazon ECS で Docker コンテナ化された Web アプリケーションを動かす - バッチ実行 - Rundeck が Kuroko2 や Barbeque に変わるだけ
Amazon ECS、Hako - ECS: EC2 インスタンス上で Docker コンテナを動かしてくれる AWS のマネージド
サービス - Hako: ECS を利用してデーモンを動かしたりワンショットのタスクを実行するための 自作ツール - https://github.com/eagletmt/hako
Hako が作られた経緯 - 基盤チームがアプリ開発のボトルネックになりたくない - マイクロサービス化で新規に Web アプリを作成することが増えた - インフラ面で強い権限を持つチームに作業依頼をするフローをできるだけ減らす
- サーバを立ててほしい、これを設定してほしい、 etc. - セルフサービス化 - 同じような作業の自動化 - Docker によりサーバのプロビジョニングは全アプリサーバで共通にできる - AWS と Docker でどんな Web アプリケーションもだいたい同じ構成になる - Route 53、ELB、RDS、ElastiCache、……
Hako - アプリケーションの定義を YAML で記述し、それを元に ECS 等の API を叩いて操 作する
- Docker イメージ、環境変数といったタスク定義 - ECS に関連付ける ELB の設定 - デプロイ中に差し込む処理の指定 - Route 53 で指定した ELB にドメインを設定したり - Jenkins から最新の安定ビルドを取得してその Docker イメージのタグを設定したり - gem で拡張可能
秘密の値 - 環境変数の一部は秘密の値を含むため Git リポジトリにコミットしたくない - データベースのパスワード - API キー
- などなど - デプロイ時に環境変数の一部を別のところから取得して埋め込みたい - 秘密の値のストレージとして HashiCorp Vault を採用
Vault による秘密の値の管理 - secret/hako/${team_name}/${app_name}/${var_name} のようなパス に秘密の値を書き込んでおく - secret/hako/${team_name} 以下にはそのチームのメンバーが読み書きで きるようにしておく
- Hako で環境変数を定義するときに #{var_name} のような文法で Vault 内の値 を参照できるように
Hako scheduler: type: ecs region: ap-northeast-1 cluster: hako-production role: ecsServiceRole
task_role_arn: arn:aws:iam::xxxx:role/EcsAwesomeApp elb_v2: vpc_id: vpc-01234567 listeners: - port: 80 protocol: HTTP - port: 443 protocol: HTTPS certificate_arn: arn:aws:acm:ap-northeast-1:xxxx:certificate/yyyy …… ECS の設定 IAM ロール ELB の設定
ECS / Docker へのパラメータ Hako …… app: image: 012345678901.dkr.ecr.ap-northeast-1.amazonaws.com/awesome-app cpu:
3072 memory: 2048 env: $providers: - type: vault addr: https://vault:8200 directory: hako/dev-infra/awesome-app DATABASE_URL: mysql2://user:#{mysql_password}@awesome-app.rds.amazonaws.com/main RAILS_ENV: production …… Docker イメージ Vault から秘密の値を 提供 秘密の値を埋め込み
Hako - これらの script は gem で拡張可能 - 社内の事情にあわせて独自の script
を用意 …… scripts: - type: jenkins_tag job: docker-awesome-app - type: route53_subdomain hosted_zone: ZABCDEFGHIJKL Jenkins の docker-awesome-app ジョブから最新の安定ビルドのリ ビジョンを取得して Docker イメージタグを書き換え elb_v2 で指定された ELB を指す awesome-app.example.com を Route 53 で設定
新規 Web アプリケーションの開発フロー - アプリケーションを書く - rails new - ヘルスチェック用のエンドポイントを用意するために
revision_plate gem を入れる - sentry-raven gem でエラーログを残せるようにする - 他アプリから使われる API は Garage で書く - Docker イメージを用意する - Dockerfile を書く - Jenkins で docker build して Amazon ECR に docker push
新規 Web アプリケーションの開発フロー - Hako の定義ファイルを書く - hako_apps リポジトリに pull-request
- Web アプリやワーカのようなデーモンの場合 - Rundeck にデプロイ、ロールバック用のジョブを登録して Ruboty を使って Slack からデプロイ - オフラインジョブの場合 - 定期実行するときは Kuroko2 に登録 - 非同期実行したい場合は barbeque_client gem を導入し Barbeque に登録 - モニタリングは Amazon CloudWatch や Datadog で
課題感 - 様々なツールを使っているため1つのアプリに関する情報を把握しきるのが困難 - 1つの GitHub リポジトリを見るだけでは終わらない - Jenkins ジョブ、Hako
の定義ファイル、Sentry のプロジェクト、CloudWatch、…… - README や社内 Wiki に毎回同じようなリンク集を書くことに - 1つの環境を作るときにやることが多い - 新機能を別ブランチで開発して普段とは別のステージング環境で動かしたい - しかしそのためには似たような Hako の定義や Jenkins ジョブ等を書かなければならない
統合コンソールの開発 - hako-console という社内 Web アプリを開発することにした - アプリケーション毎に関連するページへのリンク集を自動的に表示 - よく見る
CloudWatch メトリクスはその場で表示 - 典型的な開発での作業を一部自動化 - 1つの pull-request に紐付いたステージング環境作成を支援
hako-console
hako-console
hako-console
hako-console
hako-console Hako の定義ファイル アプリのリポジトリ Jenkins ジョブ Sentry プロジェクト Rundeck ジョブ
使っている ELB 使っている RDS
hako-console 動いてるインスタンス ECS のメトリクス (CloudWatch) コンテナ毎のメトリクス (Datadog)
hako-console ELB の情報 どのアプリが使っているか ELB のメトリクス (CloudWatch)
hako-console のポリシー - 手動で入力する箇所をなくし、可能な限り自動でページを作る - 手動メンテは必ず情報が古くなる - 実際の状態を API で取得したり、実際に使われている設定ファイルを元にすべき
情報収集手段 - Hako の定義ファイルでの指定をデータソースにする - ELB の名前や ECS のサービス名から CloudWatch
のデータを表示 - 規約 (Convention) を元に探す - Jenkins や Rundeck のジョブ一覧を API で取得して、名前で寄せる - Hako の定義ファイルに書かれた環境変数を元にする - DATABASE_URL を見て使ってる DB インスタンスを特定 - rds.amazonaws.com や cache.amazonaws.com という文字列から Amazon RDS や Amazon ElastiCache のインスタンスを特定 - Sentry DSN っぽい文字列から Sentry のプロジェクトを特定
開発フローの変化 - モニタリングはまずは hako-console を見ればよくなった - どの DB を使ってるか分かる -
その DB の負荷状況の概要も分かる - どのインスタンスで動いているか分かる - どの ELB を使っているかが分かる - その ELB のアクセス数やエラーレートの概要も分かる - 開発に必要なものも分かる - GitHub リポジトリはどこにあるのか分かる - Docker イメージを作ってる Jenkins ジョブはどれなのか分かる - 新規に参加する開発者が把握しやすい
pull-request staging
pull-request staging - 開発中の機能をステージング環境で動かしたい - 本番と同じようなデータや複数人で使ってる状況で動かしたい - ディレクターや他のスタッフに使ってみてもらいたい - 普段とは別のステージング環境の作成を楽にしたい
- 機能開発は pull-request で進む - pull-request と同じライフサイクルの環境を作ればいいのではないか
pull-request staging - hako-console に GitHub の pull-request に関するイベントを受けとる webhook
を 用意 - “make staging please” とコメントするとその pull-request のブランチから専用のステージング環境 が自動的に作成される - pull-request がクローズ (マージ含む) されたらそのステージング環境は破棄
pull-request staging make staging please
pull-request staging merged
pull-request staging - 作成時 - Jenkins ジョブを複製して push する Docker
イメージの名前を置換 - YAML 内で指定している Docker イメージを↑で置換したものに変更 - Rundeck ジョブを複製して↑で push した YAML ファイルでデプロイするように変更 - ここで作った Jenkins ジョブや YAML ファイルや Rundeck ジョブを DB に保存 - 削除時 - hako remove で ECS からアプリケーションを削除 - DB に保存されたジョブや YAML ファイルを削除
分散トレーシング
マイクロサービス化の課題 - マイクロサービス化により、システム全体を把握することが難しくなる - 障害発生時の原因究明が難しい、システム全体でのパフォーマンスの分析が難しい - アプリも DB も負荷は高くなってないのに何故遅くなった ?
- マイクロサービス化にあたって必ず出てくる問題
分散トレーシング - システム外からのあるリクエスト (例: エンドユーザ) を起因としたシステム内のサー ビスへのリクエストを追跡できるようにするもの - どのサービスに何回リクエストしているのか -
各サービスへのリクエストにどれくらい時間がかかってるのか - 最初にエラーを返したサービスはどれなのか
分散トレーシング - 最初のリクエストを受けたときに「トレース ID」を発行し、他サービスへリクエストす るときのヘッダにトレース ID を付加する - トレース ID
つきのリクエスト、レスポンスのデータを分散トレーシングシステムに送信 app-A app-B app-C app-D トレーシング システム エンドユーザ トレース ID を発行 trace-X trace-X trace-X トレースデータ - トレース ID - リクエスト - レスポンス
AWS X-Ray - 分散トレーシングシステムとして AWS X-Ray を採用 - トレースデータを送信する SDK
で Ruby の公式サポートは現時点では無し - @taiki45 が非公式の gem を作成 https://github.com/taiki45/aws-xray
E AWS X-Ray + ECS - SDK から送信されてくるデータを AWS X-Ray
に送信するデーモンを一緒に起動 する - このデーモンは公式のものが用意されているのでそれを Docker イメージへ - アプリには aws-xray gem を導入して一緒に起動している xray コンテナにデータ を送信する aws-xray gem app container xray daemon xray container AWS X-Ray ECS task
AWS X-Ray + ECS サービスマップ
AWS X-Ray + ECS 障害時 ダメそうなサービスが分かる
AWS X-Ray + ECS トレースの詳細
AWS X-Ray + hako-console X-Ray のデータを使ってどのアプリとどのアプリが通信しているのかを表示
今後やっていきたいこと
今後やっていきたいこと - サービスメッシュ - 1つのアプリが複数の別のアプリの Web API を使っている状況 - 各アプリがどれくらいリクエストしているのかメトリクスを知りたい
- うまく接続したい - 接続先が過負荷でダウンしたときは接続を止めたい (サーキットブレーカー ) - 適切にリトライしたい - タイムアウトの値を調整したい - 接続先をうまく管理したい (サービスディスカバリ ) - @taiki45 が構築中
今後やっていきたいこと - RPC - Garage による REST API の限界 -
スキーマがほしい - どんな JSON が返ってくるのか、各フィールドの型は何なのか - REST へのマッピングが困難 - GET とか POST とか考えずにメソッドのようなエンドポイント - クライアントのコード生成 - gRPC が候補か?