Publicité

はてなにおける継続的デプロイメントの現状と Docker の導入

Software engineer à R
13 Jan 2015
Publicité

Contenu connexe

Présentations pour vous(20)

En vedette(20)

Publicité

Similaire à はてなにおける継続的デプロイメントの現状と Docker の導入(20)

Publicité

Dernier(20)

はてなにおける継続的デプロイメントの現状と Docker の導入

  1. id:nobuoka (@nobuoka) 株式会社はてな 2015-01-11 Jenkins ユーザ・カンファレンス 2015 東京 はてなにおける継続的デプロイメント の現状と Docker の導入
  2. id:nobuoka Blog : http://vividcode.hatenablog.com/ Twitter : https://twitter.com/nobuoka GitHub : https://github.com/nobuoka ● 2012 – 2014 : はてなブックマーク – ブクマ本体、アプリ、Presso など ● 2014 – 現在 : 少年ジャンプルーキー – WJ 編集部が運営するマンガ投稿サービス ● 株式会社はてな ● アプリケーションエンジニア
  3. 今日の話 1.はてなのサービス開発と Jenkins ● 全社的な話。 2.ジャンプルーキーの開発フローと Jenkins ● ジャンプルーキーのチームを例に開発フローを 紹介。 3.Docker コンテナによる確認環境と Jenkins ● 動作確認用の web アプリケーション。 ● Jenkins 上で Docker ビルド。
  4. はてなのサービス開発と Jenkins はてな全体におけるサービス開発と Jenkins との関わりについて紹介し ます。
  5. はてなのサービス など
  6. ブックマーク・ブログなど ● Perl ● はてなのサービス開発の主流 ● コンパイルのプロセスは基本的に不要 – JS や CSS の静的ファイルの変換などはある ● テストの実行や静的ファイル生成、デプロイ などで Jenkins を活用 ● 少年ジャンプルーキーもこの流れ – 後で詳しく
  7. 参考: ブログの開発プロセス https://speakerdeck.com/shibayu36/hate naburogutimufalsekai-fa-hurotogithub https://speakerdeck.com/onishi/hatena -blog-development-flow
  8. Mackerel ● サーバー管理サービス ● 2014 年リリース ● Scala ● サーバーサイドのアプリケーションを動かす ためにコンパイルが必要 – これまでのはてなのサービスとは違って Jenkins でコンパイルをしたりしてる
  9. Mackerel
  10. 参考: Mackerel の話 (Jenkins の話も少し) https://speakerdeck.com/hakobe/scala-in-perl-company
  11. 各サービスと Jenkins ● それぞれのサービスで Jenkins を活用 ● 昔: master/slave 構成の Jenkins 1 組 ● → 最近はサービスごとに Jenkins を用意 ● サービスごとに異なる環境 – あるサービス用に変更を加えると別のサービス のテストが動かなくなる、とか ● 関係者が少ない方がメンテナンスしやすい
  12. なんのための Jenkins か ● ソフトウェア進化を継続するため – はてなダイアリーは 10 年超 – はてなブックマークは 10 年 ● テスト、ビルド、デプロイ ● 意識しなくてもテストが実行される環境 ● 面倒な手順の自動化
  13. 特にテスト ● 開発時は各自のマシンで – OS X、Linux、Windows ● 開発者のマシン上ではテストに通っても実際 の環境では動かない可能性 ● → 本番に近い環境でのテスト実行 ● 面倒なのでいちいち全テスト実行しない ● → 自動でのテスト実行
  14. Jenkins の管理 ● Chef で Jenkins の環境を構築 – 本番サーバーも Chef で構築 ● Jenkins 自体だけでなく、各プロジェクトのビ ルドやテストに必要なコマンドやホストの設 定も Chef で行う ● 本番サーバーと同等の環境を実現
  15. Jenkins 使用の方針 ● Jenkins の設定を複雑にしない – 秘伝のタレ問題 – コマンド一つで処理を実行できるように – 環境準備とかも ● 例 : 処理の内容は Shell スクリプトファイル に記述してプロジェクトのリポジトリに入れる
  16. スマートフォンアプリと Jenkins ● Android アプリ → Gradle が標準になりビ ルドやテストの自動化がしやすく ● Jenkins 上でのテスト実行 – Android Emulator Plugin – Android SDK は用意してくれる – 必要なコンポーネントは? → Gradle プラグイ ンでインストール可能! ● iOS アプリも含め、これからという段階
  17. ジャンプルーキーの開発プロセスと Jenkins はてなのサービス開発プロセスの中での Jenkins の役割を 具体的に紹介。
  18. 少年ジャンプルーキー ● ユーザーによるマンガ投稿・公開サービス ● 2014 年 11 月末にリリース ● 少年ジャンプ編集部 ● 漫画雑誌アプリ 「少年ジャンプ+」 内
  19. 少年ジャンプルーキー ● ユーザーによるマンガ投稿・公開サービス ● 2014 年 11 月末にリリース ● 少年ジャンプ編集部 ● 漫画雑誌アプリ 「少年ジャンプ+」 内 2014 年末
  20. 少年ジャンプルーキーの開発・運用 ● 開発・運用 : はてな ● ディレクター 1 人、デザイナ 1 人 ● エンジニア数名 (開発・運用) ● 最近のはてなでの開発・運用を踏襲・改善
  21. サーバーサイド ● 言語: Perl – ビルドプロセスは不要 ● データストレージ – MySQL – Redis – Amazon S3
  22. フロントエンド ● HTML は生 ● TypeScript – TypeScript → JS → minified JS – ビルドプロセスが必要 (開発者の手元 + Jenkins) ● LESS – LESS → CSS – ビルドプロセスが必要 (開発者の手元)
  23. ビルドツールやデプロイツール ● ビルドツール: gulp (Node.js) – TS → JS や LESS → CSS – JS テスト実行 – 静的ファイルにダイジェストハッシュ付与 ● デプロイ: Capistrano 3 (Ruby) ● バージョン管理: Git – 中央リポジトリは GitHub;Enterprise
  24. 開発に用いるツール ● はてなグループ : 日記 + Wiki システム – ドキュメント管理 ● Slack : チャットツール ● Trello : タスク管理 ● GitHub;Enterprise : コード管理 (レビュー 等) ● Jenkins
  25. 開発プロセス概要 ● スクラム、2 週間 1 スプリント ● リリースは毎週 – 自社サービスではないのでどんどん出すという 感じではない – だが、常に最新の機能をリリースできる状態を 保つ ● 今回はタスク管理などにはあまり触れずに 開発者目線で
  26. master staging devel features ブランチモデル リリース
  27. ブランチモデル ● master ブランチ – 本番反映対象 ● staging 系列ブランチ (例: staging-20150101-000000) – 本番反映ごとに別ブランチ名で毎回作成 ● devel ブランチ – リリース可能なものをマージ ● features – 開発ブランチ
  28. ブランチモデル ● Git-flow のブランチモデル ● devel ブランチは常にリリース可能な状態に 保つ ● リリース済みの機能の緊急修正は master ブランチからブランチを切って行う
  29. 新機能開発、バグ修正
  30. master staging devel features ブランチを作成して開発開始
  31. pull request を作成 ● 開発中に立てるかどうかは任意 – コードレビュー時には必須 ● 開発中の様子が見えやすい ● 開発中のコードについて議論しやすい ● Jenkins によるテストの結果の可視化
  32. 開発時の Jenkins の役割 ● Push されるごとにライブラリ更新、JS minify – 必要な場合のみ – 結果をコミット ● Push されるごとにテストを実行 – 失敗時には通知する – Slack、GH;E ● 動作確認のために開発用ホストにデプロイ (Docker 使用、後述)
  33. Push されるごとにビルド実行 ● Jenkins の GitHub Plugin ● GH;E の Server Hook ● 処理内容は script/jenkins.sh に記述 – Static ファイルの変換処理 → コミット、or – テスト実行 (Perl、JS)
  34. GH;E のコミットへの通知 ● Shell スクリプトの中に記述 – ブクマなどでは通知用ジョブを下流に用意 curl -X POST -H "Authorization: token $token" https://github- enterprise.example.com/api/v3/repos/example/Exa mple-Project/statuses/$git_head -d "{ "state": "success", "target_url": "${BUILD_URL}", "description": "The build has succeeded." }"
  35. Slack への通知 ● Slack の Integrations ● Jenkins の Slack Notification Plugin
  36. 良いところと課題 ● ○ push したら自動でテスト実行 ● ○ 失敗時の通知がされる – × Slack と GH;E だけなので弱い → XFD? – × GH;E への通知がビルド処理の中にある ● ○ ファイルの変更結果をコミット ● × ファイル変更とテスト実行が同じ Shell ス クリプトになっていて管理しづらい ● ○ コマンド 1 つで確認用にデプロイ
  37. レビューとマージ
  38. 開発が完了したらコードレビュー ● Pull request 上でコメントを残してやりとり ● 問題がある箇所は修正・変更 – ここでの Jenkins の役割は開発時と同じ ● レビュアにとってテスト結果が GH;E 上で確 認できるのが便利 – テストに通っているかどうかすぐにわかる
  39. レビュー後 devel ブランチにマージ ● Pull request のマージボタンでマージ ● 先にコンフリクト解消が強制されるのでコン フリクト解消ミスをしづらい ● テスト失敗時にわかりやすい
  40. master staging devel features レビュー後 devel ブランチにマージ
  41. 良いところ ● ○ レビュアがテスト結果を確認しやすい ● ○ テストに落ちているのに気付かずマージ ということがない – devel ブランチをリリース可能な状態に保てる ● ○ マージボタン強制によりコンフリクト解消 のミスをしづらい
  42. デプロイ
  43. 本番リリース用 pull request 作成 ● Staging 系列のブランチを作成して master ブランチに向けた pull request を作成 – ブランチ作成、pull request 作成をコマンド 1 つで実行 ● Staging 系列ブランチを staging 環境にデ プロイして動作確認 – デプロイは Capistrano 3
  44. master staging devel features 本番リリース用 pull request 作成
  45. 本番リリース用 pull request 作成
  46. Staging の動作確認後にリリース ● 本番リリース用 pull request のマージボタ ンで master ブランチにマージ ● Capistrano 3 で本番デプロイ
  47. master staging devel features Staging の動作確認後にリリース
  48. 良いところと課題 ● ○ 本番リリース用 pull request をコマンド 1 つで作成できる ● ○ デプロイもコマンド 1 つ ● × staging 環境へのデプロイが自動化され ていない
  49. まとめと今後
  50. 少年ジャンプルーキーの開発プロセス ● Jenkins、GH;E の活用、連携 – テスト (インスペクション含) の自動実行でコー ド品質を保つ – ファイル変更処理 ● デプロイは少ないコマンドで完了 – Jenkins は使っていない ● 継続的なソフトウェア進化の礎 – 改善し続けることが大事
  51. 今後: Jenkins Workflow Plugin 検討 ● 2014 年 12 月にバージョン 1.0 リリース ● Scripted control flow – Shell スクリプトに書いてあることを Workflow Plugin のスクリプトに置きかえる ● Pause and resume execution – ユーザーとのインタラクションの機能もあるので デプロイ処理を Jenkins に乗せやすい
  52. Docker コンテナによる確認環境と Jenkins 開発中の機能を確認するための環境を準備する方法の紹介。
  53. たとえばこんなこと
  54. D E 作品をお気に入りする機能を 作るで! あれが云々これが云々や。 機能開発して よっしゃ、作るで! …… できたで! D ほんなら次回リリースするで!
  55. D E 作品のお気に入り機能、ここ がこうなってこうやと思ってた んやけどなー。 リリース直前に初めて動作確認 リリース前の動作確認や!! E なんやて!!
  56. なんてことはさすがにないと思うが
  57. 開発した機能の確認が遅れると困る ● 無駄な手戻り ● 開発スピードの低下 ● 特に UI/UX 周り ● 開発中の機能を確認できる環境は便利 – チーム内 : 動作を見ながら開発を進める – ステークホルダーによる確認
  58. 目的 開発中の機能の動作や UI/UX を 確認するための Web アプリケー ションを手軽に動かしたい 社内では devhost と呼んでいる
  59. master staging devel }features ココが 対象 対象とするブランチ
  60. 前提として ● 開発者自身はローカルホスト上でアプリケー ションを動かして開発 ● Devhost は誰のために? – チーム内のメンバー (非開発者・遠隔地) – チーム外 ● → 社外からも見えるように (状況次第だが) ● ブランチ名に対応するドメイン名 ● ストレージは開発用に 1 つ
  61. https://{branch-name}.dev.example.com/
  62. 既存の方法 (はてなブックマークなど) ● 開発用サーバで複数アプリケーション起動 ● 別ポート番号を使用 (or Unix ドメインソケット) ● ポート番号解決 : Nginx 上の Lua で https://{branch-name}.dev.example.com/ → {ポート 番号} 開発用 proxy Nginx 開発用サーバー Nginx アプリケーション アプリケーション アプリケーション ポート番号 解決
  63. 課題 ● 同じ環境を複数アプリケーションが使用する ので面倒だったり問題が起こったり – ファイルシステム、ライブラリ等 ● ブランチ名とポート番号の対応付けが面倒 – ファイルを使って管理するなど
  64. そこで Docker Engine の登場
  65. Docker Engine とは? ● コンテナ型の仮想化技術 – 環境を分離するという目的に適す ● ゲストの状態を Docker イメージとしてバー ジョン管理 ● Dockerfile にビルド処理を記述して Docker イメージをビルド ● Docker イメージをもとに Docker コンテナ 内でアプリケーションを動作させる
  66. コンテナ型の仮想化 物理マシン ハイパーバイザ 仮想マシン ゲスト OS ● ユーザー空間を分けてリソースを制限する – ファイルシステム、プロセス、など 物理マシン Kernel ユーザー 空間 ユーザー 空間 コンテナ型の仮想化完全仮想化
  67. Docker イメージとコンテナ Dockerfile Docker イメージ docker build Docker コンテナ Docker コンテナ docker run コンテナが生成され 中でプロセスが動く
  68. Docker コンテナを用いた確認環境 ● 開発用サーバで複数 Docker コンテナ起動 ● 別ポート番号を使用 ● ポート番号解決 : Docker API を使用 https://{branch-name}.dev.example.com/ → {ポート 番号} 開発用 proxy Nginx 開発用サーバー Proxy 用 Plack アプリケーション Docker コンテナ Docker コンテナ Docker コンテナ Docker API ポート番号解決ポート番号解決
  69. Docker API を用いたポート番号解決 ● ホスト側のポート番号が適当に割り当て – コンテナ内の web アプリケーションは 80 番 ポートをリッスン – Docker コンテナは 80 番を EXPOSE ● 各ブランチからイメージをビルドする際、ブラ ンチ名に対応したタグをイメージに付ける ● ホスト名からブランチ名を抽出 → Docker API により対応するタグ名のイメージのコン テナを探す → ポート番号取得
  70. Docker API を叩くコードの例 my $furl = Furl->new(); my $uri = do { local $_ = $docker_remote_api->clone; $_->path('/containers/json'); $_; }; my $body = decode_json $furl->get($uri)->content }; (grep { $_->{Image} eq "$host:latest" } @$body)[0];
  71. Docker コンテナの生成
  72. Dockerfile を準備して docker build ● ライブラリ等インストール → プロジェクトの ファイルコピー → コマンド登録 FROM debian:stable # (略) # config/setup.sh は本番サーバー構築時にも使用される初期化スクリプト。 COPY script/setup.sh /app/shared/script/setup.sh RUN sh /app/shared/script/setup.sh # (略) # Source RUN mkdir -p /app/src COPY . /app/src # (略) WORKDIR /app/src EXPOSE 80 CMD ["supervisord", "-c", "/app/src/config/docker/webapp/supervisord.conf"]
  73. イメージビルドに時間がかかる問題 ● debian:stable から最後までビルドすると 30 分程度かかる – apt-get や Perl のインストール – Perl ライブラリのインストール
  74. イメージビルド時のキャッシュの活用 ● Docker イメージのビルドにキャッシュが効く ● デフォルトで有効 ● COPY すると (変更されてると) キャッシュ効 かない ● プロジェクト全体を COPY する前に、初期化 処理用のファイルだけを COPY – それらのファイルが変更されていなければ初期 化処理のキャッシュが有効に!
  75. # config/setup.sh は本番サーバー構築時にも使用される # 初期化スクリプト。 COPY script/setup.sh /app/shared/script/setup.sh RUN sh /app/shared/script/setup.sh # CPAN Modules RUN mkdir -p /app/shared/carton WORKDIR /app/shared/carton COPY cpanfile /app/shared/carton/cpanfile COPY cpanfile.snapshot /app/shared/carton/cpanfile.snapshot RUN carton install --deployment
  76. キャッシュ効果でビルド時間短縮!!
  77. Jenkins 上でのビルドとデプロイ ● Jenkins 上で – docker build – docker rm -f : 同じブランチのコンテナを止める – docker run ● 実際のコマンドは rake タスクにしてある – ブランチ名 → タグ名変換処理 – 同じブランチの古いコンテナが動いてるか調査 – Shell スクリプトより Ruby の方が書きやすい
  78. Jenkins 上でのビルドとデプロイ 1. git clone イメージ 2. docker build コンテナ 3. docker rm / docker run 開発用サーバー 開発用サーバー内で完結 しているので単純
  79. ビルド開始方法 ● 現在は手動でビルド開始 – Jenkins API 叩く or Web UI から – 対象ブランチをパラメータで受け取り ● 本来は次のようにしたい – devel ブランチへの push で自動的にビルド – 既に devhost が立っているブランチへの push で自動的にビルド
  80. 対象ブランチのパラメータ化 POST /job/{job-name}/buildWithParameters?branch_name={branch-name}
  81. なぜ Jenkins でビルドするのか ● 同じ環境でビルド処理を行わせたい ● ビルドの管理 ● 変遷 – Capistrano などで直接開発用サーバー上で ビルド → 複数人が同時に使うと破滅 – Docker API を使う → キャッシュが効きづらく て困る
  82. 今後 ● devel ブランチの自動デプロイ ● Pull request との関連付けを強める – コメントで新規 devhost 作成 (?) – close 時に自動で devhost 破棄 – 破棄が結構面倒なので自動化したい ● ビルド後にコンテナ内でテストしてそれから デプロイ
  83. 小ネタ: 確認環境用の favicon ● ローカルホスト上の web アプリケーションや 確認用の web アプリケーション ● 本番と確認用を間違えたりしてしまう ● Favicon を変えることでタブで識別しやすく
  84. 小ネタ: 確認環境用の favicon
  85. まとめ
  86. はてなにおける Jenkins ● GH;E への push に応じたテスト自動実行 や確認用ホストへのデプロイなど ● 開発プロセスの中でビルドやテストの実行を 指揮する大切な役割を果たしている – 少年ジャンプルーキーでの例を紹介 ● Jenkins で Docker ビルドしてデプロイする という仕組みで手軽に確認環境を用意
  87. We are hiring!
Publicité