Slide 1

Slide 1 text

デプロイ元をCircleCIから Herokuに乗り換えた Heroku Meetup #25 "Heroku Ghost" 2019-07-26 @masutaka

Slide 2

Slide 2 text

HerokuJP-UG Slackにて https://herokujp-ug.slack.com/archives/C9LRC3M25/p1560763558027800

Slide 3

Slide 3 text

モチベーション

Slide 4

Slide 4 text

モチベーション ● 今関わっているサービスのデプロイフローが複雑だと感 じていた ● Heroku Meetup #23 阿部さんのセッション『正しく理 解するHeroku Flow』 ○ CIが通ったらHerokuのAutomatic deploysを使ってデプロイすることがベストプラクティ ス ● 出来ればそれに従いたい、いつかはやろうと思っていた https://herokujp.doorkeeper.jp/events/82754

Slide 5

Slide 5 text

Heroku Flow https://www.heroku.com/flow

Slide 6

Slide 6 text

なぜCircleCIからデプロイしていたか ● 元々はHeroku上でデプロイしていた ● デプロイスピード向上のためにCircleCIでのビルドに切 り替えたそう ○ 私がチームに入る前の話 ○ 当時の記録によると、2分7秒に短くなったとのこと。変更前のデプロイ時間は不明

Slide 7

Slide 7 text

現在関わっているサービス

Slide 8

Slide 8 text

EC Booster 国内初のGoogleショッピング広告自動運用ツール

Slide 9

Slide 9 text

今回の技術スタック Heroku App Web Dyno GraphQL Client (apollo-client) GraphQL Server (graphql-ruby on Rails) Worker Dyno Chrome (headless mode) chromedriver sidekiq Heroku Postgres Heroku Redis

Slide 10

Slide 10 text

1つのHeroku Appに 割とたくさん詰まっています。

Slide 11

Slide 11 text

以前のデプロイフロー

Slide 12

Slide 12 text

以前のbuildpack 1. heroku/ruby 2. heroku-buildpack-google-chrome ○ https://github.com/heroku/heroku-buildpack-google-chrome.git 3. heroku-buildpack-chromedriver ○ https://github.com/heroku/heroku-buildpack-chromedriver.git

Slide 13

Slide 13 text

以前のデプロイフロー 1. CIが通る 2. Assets(.js,.css,.svg,...)を作成 3. 作成したAssetsをgit commit 4. git push heroku master 5. Slugの作成 6. Release phase 7. Dynoの起動 8. Chromeとchromedriverのvalidate 9. Bugsnagにcommit hashをcurlで通知 10. Bugsnagにsourcemapをアップロード 高速化のつもりが、 効果をなさなくなっ ていた(調査の過程 で分かった)

Slide 14

Slide 14 text

使用していたデプロイスクリプト(135行)

Slide 15

Slide 15 text

何が悪かったのか

Slide 16

Slide 16 text

何が悪かったのか ● Heroku Flowから反している ● 属人化したデプロイスクリプト ● CircleCIのコンテナを無駄に消費する ● Herokuだけに存在するgitのcommit hashが出来る ● ReviewApp作成に無駄がある(後述)

Slide 17

Slide 17 text

ReviewApp作成に無駄がある 1. ReviewApp作成開始 2. Slugの作成 3. Release phase 4. ReviewApp作成完了 1. CI 2. Deploy 5. Slugの作成 6. Release phase 7. ReviewApp再起動 git push Assetsがないの で、まだ起動でき ない Assetsが作られ、 ようやく起動でき た PR作成をトリガーに自 動的に開始する。 CircleCIとは順序依存 なく始まる

Slide 18

Slide 18 text

現在のデプロイフロー

Slide 19

Slide 19 text

現在のbuildpack 1. heroku/nodejs ← 追加 2. heroku/ruby 3. heroku-buildpack-google-chrome ○ https://github.com/heroku/heroku-buildpack-google-chrome.git 4. heroku-buildpack-chromedriver ○ https://github.com/heroku/heroku-buildpack-chromedriver.git

Slide 20

Slide 20 text

現在のデプロイフロー 1. CIが通る 2. Slugの作成 a. Assets(.js,.css,.svg,...)を作成 b. Bugsnagにsourcemapをアップロード 3. Release phase a. Chromeとchromedriverのvalidate 4. Dynoの起動 5. deployhooks:httpがBugsnagにcommit hash を通知 Heroku Automatic deploy

Slide 21

Slide 21 text

現在のデプロイスクリプト なし

Slide 22

Slide 22 text

改善されて普通になったReviewApp作成 1. ReviewApp作成開始 2. Slugの作成 3. Release phase 4. ReviewApp作成完了 1. CI PR作成をトリガーに自 動的に開始する。 CircleCIとは順序依存 なく始まる

Slide 23

Slide 23 text

デプロイ時間の変化

Slide 24

Slide 24 text

以前のデプロイ時間は6分ほど

Slide 25

Slide 25 text

現在のデプロイ時間も6分ほど

Slide 26

Slide 26 text

デプロイ時間の変化 ● 大きな劣化もなく、Herokuに乗り換えられた ○ storybook作成をHerokuからCircleCIに変更するなど、細かいチューニングは行った ○ CIやデプロイまわりの処理は徹底的に調べた

Slide 27

Slide 27 text

得られた知見

Slide 28

Slide 28 text

全般的な知見やメリット ● CircleCIからgit pushするメリットはない ○ CircleCI上でのgit commitは論外 ● Heroku Automatic deployは賢い ○ 連続したデプロイを1つにまとめることがある ● GitHubから見るとCI時間が短くなる ○ CircleCIのデプロイジョブがなくなるため ● Review Appは作り直せば普通に動く ○ デプロイスクリプトとはなんだったのか

Slide 29

Slide 29 text

heroku/nodejs buildpackの知見 ● package.jsonのenginesに書かれたバージョンの Node.jsとnpmをインストールする ● package.jsonにbuild scriptが定義されていれば、npm install後に実行する ○ ただし、heroku-postbuild scriptも定義されていれば、こちらが実行される ● package.jsonのdevDependenciesはSlugに含まれない https://devcenter.heroku.com/articles/nodejs-support

Slide 30

Slide 30 text

heroku/ruby buildpackの知見 ● すでにNode.jsがインストールされていれば、Node.jsを インストールしない ● ゆえにheroku/nodejs buildpackとの順番が非常に大事 1. heroku/nodejs 2. heroku/ruby ● Node.jsがインストールされていなければ、固定バージョ ンのNode.jsとyarnをインストールする。npmはインス トールしない https://devcenter.heroku.com/articles/ruby-support

Slide 31

Slide 31 text

ヒヤリ

Slide 32

Slide 32 text

ヒヤリ ● Bugsnag sourcemapアップロード時にはgitのcommit hashが必要 ● $HEROKU_SLUG_COMMITを使う予定だった ○ Heroku lab runtime-dyno-metadataが提供する ● しかし、Slugビルド時には定義されていなかった ○ 使い勝手が落ちるので、全部revertすることも覚悟した ● Slugビルド時には$SOURCE_VERSIONが使えた ○ https://devcenter.heroku.com/articles/buildpack-api#bin-compile-summary

Slide 33

Slide 33 text

教訓 ● Herokuのドキュメントは充実している。まずは読むべし ○ よく読んだらBuildpack APIのドキュメントに$SOURCE_VERSIONが書いてあった ○ https://devcenter.heroku.com/articles/buildpack-api

Slide 34

Slide 34 text

あわせて読みたい ● buildpackのソースコードを読むとなお良い。発見が多い ○ 例えばbuildpack-stdlibの存在 ○ https://github.com/heroku/buildpack-stdlib

Slide 35

Slide 35 text

課題

Slide 36

Slide 36 text

課題 ● まだHeroku Flowに乗りきれていない ○ Promoteを使えていない ○ ステージごとにCDNのURLを切り替えているため ○ CircleCIでgit commitしていた負債 ○ CDNはCloudFrontを使っており、OriginをHerokuにしている

Slide 37

Slide 37 text

自己紹介

Slide 38

Slide 38 text

自己紹介 ● 増田貴士(@masutaka) ● Heroku Meetupは前々回#23から参加 ● 株式会社フィードフォース ● EC Boosterの裏方エンジニア ● EC Boosterはバッチ処理が多い ● 安定したバッチ処理を実行するための基盤を模索中

Slide 39

Slide 39 text

ご清聴ありがとうございました

Slide 40

Slide 40 text

おまけ

Slide 41

Slide 41 text

おまけ1: Chromeとchromedriverのvalidate release: bin/release # Web app web: bundle exec puma -C config/puma.rb worker: PROCESS_TYPE=worker bundle exec sidekiq -C config/sidekiq.yml # Ad app ad_worker: PROCESS_TYPE=ad_worker bundle exec sidekiq -C config/sidekiq.yml #!/bin/sh -eu # バイナリが実行できるかを確認。失敗したらこの スクリプトは即時にエラー終了する。 chromedriver --version $HOME/.apt/opt/google/chrome/chrome --version bin/rails db:migrate db:seed bin/release Procfile

Slide 42

Slide 42 text

おまけ2: Chromeとchromedriverをvalidateしている理由 ● 以前、起動出来ないChromeが本番環境にリリースされてしまった ○ 原因: https://github.com/heroku/heroku-buildpack-google-chrome/issues/56 ● せめて動くバイナリであってほしい・・・! ● PR作った ○ https://github.com/heroku/heroku-buildpack-google-chrome/pull/72 ■ 2ヶ月ほど経過 ○ https://github.com/heroku/heroku-buildpack-chromedriver/pull/16 ■ 複雑になりすぎて諦めた ■ Buildpackに依存関係を付ける機能があれば解決できた

Slide 43

Slide 43 text

おまけ3: Chrome & chromedriver buildpackの細かすぎる知見 ● chromedriver buildpackは暗黙的にChrome buildpack に依存している ● chromedriver buildpackだけをインストールしても、必 要な.soが足りない ● Chrome buildpackもインストールして初めて、ELFの実 行ファイルとして使うことが出来る https://github.com/heroku/heroku-buildpack-chromedriver/pull/16

Slide 44

Slide 44 text

②マージ 以前のブランチ戦略 各ブランチ master ブランチ production ブランチ production demo staging Revew App1 Revew App2 Revew AppN ①デプロイ ④マージ (git-pr-release) ③デプロイ ⑥デプロイ https://github.com/motemen/git-pr-release ︙

Slide 45

Slide 45 text

②マージ 現在のブランチ戦略 各ブランチ master ブランチ production demo staging Revew App1 Revew App2 Revew AppN ①デプロイ ③デプロイ Review Appを極 力productionに 近づける。 ちょっと豪快かな。。。 ︙ Slugレベルで同じものを本 番環境に出せていない