89
id:nobuoka (@nobuoka) 株式会社はてな 2015-01-11 Jenkins ユーザ・カンファレンス 2015 東京 はてなにおける継続的デプロイメント の現状と Docker の導入

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

Embed Size (px)

Citation preview

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

id:nobuoka (@nobuoka)株式会社はてな

2015-01-11 Jenkins ユーザ・カンファレンス 2015 東京

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

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

id:nobuoka

Blog : http://vividcode.hatenablog.com/Twitter : https://twitter.com/nobuokaGitHub : https://github.com/nobuoka

● 2012 – 2014 : はてなブックマーク– ブクマ本体、アプリ、Presso など

● 2014 – 現在 : 少年ジャンプルーキー– WJ 編集部が運営するマンガ投稿サービス

● 株式会社はてな● アプリケーションエンジニア

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

今日の話

1.はてなのサービス開発と Jenkins● 全社的な話。

2.ジャンプルーキーの開発フローと Jenkins● ジャンプルーキーのチームを例に開発フローを

紹介。

3.Docker コンテナによる確認環境と Jenkins● 動作確認用の web アプリケーション。● Jenkins 上で Docker ビルド。

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

はてなのサービス開発とJenkinsはてな全体におけるサービス開発と Jenkins との関わりについて紹介します。

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

はてなのサービス

など

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

ブックマーク・ブログなど

● Perl● はてなのサービス開発の主流● コンパイルのプロセスは基本的に不要

– JS や CSS の静的ファイルの変換などはある● テストの実行や静的ファイル生成、デプロイ

などで Jenkins を活用● 少年ジャンプルーキーもこの流れ

– 後で詳しく

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

Mackerel

● サーバー管理サービス● 2014 年リリース● Scala● サーバーサイドのアプリケーションを動かす

ためにコンパイルが必要– これまでのはてなのサービスとは違って

Jenkins でコンパイルをしたりしてる

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

Mackerel

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

参考: Mackerel の話 (Jenkins の話も少し)

https://speakerdeck.com/hakobe/scala-in-perl-company

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

各サービスと Jenkins

● それぞれのサービスで Jenkins を活用● 昔: master/slave 構成の Jenkins 1 組● → 最近はサービスごとに Jenkins を用意● サービスごとに異なる環境

– あるサービス用に変更を加えると別のサービスのテストが動かなくなる、とか

● 関係者が少ない方がメンテナンスしやすい

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

なんのための Jenkins か

● ソフトウェア進化を継続するため– はてなダイアリーは 10 年超– はてなブックマークは 10 年

● テスト、ビルド、デプロイ● 意識しなくてもテストが実行される環境● 面倒な手順の自動化

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

特にテスト

● 開発時は各自のマシンで– OS X、Linux、Windows

● 開発者のマシン上ではテストに通っても実際の環境では動かない可能性

● → 本番に近い環境でのテスト実行● 面倒なのでいちいち全テスト実行しない● → 自動でのテスト実行

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

Jenkins の管理

● Chef で Jenkins の環境を構築– 本番サーバーも Chef で構築

● Jenkins 自体だけでなく、各プロジェクトのビルドやテストに必要なコマンドやホストの設定も Chef で行う

● 本番サーバーと同等の環境を実現

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

Jenkins 使用の方針

● Jenkins の設定を複雑にしない– 秘伝のタレ問題– コマンド一つで処理を実行できるように– 環境準備とかも

● 例 : 処理の内容は Shell スクリプトファイルに記述してプロジェクトのリポジトリに入れる

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

スマートフォンアプリと Jenkins

● Android アプリ → Gradle が標準になりビルドやテストの自動化がしやすく

● Jenkins 上でのテスト実行– Android Emulator Plugin– Android SDK は用意してくれる– 必要なコンポーネントは? → Gradle プラグイ

ンでインストール可能!● iOS アプリも含め、これからという段階

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

ジャンプルーキーの開発プロセスと Jenkinsはてなのサービス開発プロセスの中での Jenkins の役割を具体的に紹介。

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

少年ジャンプルーキー

● ユーザーによるマンガ投稿・公開サービス● 2014 年 11 月末にリリース● 少年ジャンプ編集部● 漫画雑誌アプリ 「少年ジャンプ+」 内

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

少年ジャンプルーキー

● ユーザーによるマンガ投稿・公開サービス● 2014 年 11 月末にリリース● 少年ジャンプ編集部● 漫画雑誌アプリ 「少年ジャンプ+」 内

2014 年末

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

少年ジャンプルーキーの開発・運用

● 開発・運用 : はてな● ディレクター 1 人、デザイナ 1 人● エンジニア数名 (開発・運用)● 最近のはてなでの開発・運用を踏襲・改善

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

サーバーサイド

● 言語: Perl– ビルドプロセスは不要

● データストレージ– MySQL– Redis– Amazon S3

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

フロントエンド

● HTML は生● TypeScript

– TypeScript → JS → minified JS– ビルドプロセスが必要 (開発者の手元 + Jenkins)

● LESS– LESS → CSS– ビルドプロセスが必要 (開発者の手元)

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

ビルドツールやデプロイツール

● ビルドツール: gulp (Node.js)– TS → JS や LESS → CSS– JS テスト実行– 静的ファイルにダイジェストハッシュ付与

● デプロイ: Capistrano 3 (Ruby)● バージョン管理: Git

– 中央リポジトリは GitHub;Enterprise

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

開発に用いるツール

● はてなグループ : 日記 + Wiki システム– ドキュメント管理

● Slack : チャットツール● Trello : タスク管理● GitHub;Enterprise : コード管理 (レビュー

等)● Jenkins

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

開発プロセス概要

● スクラム、2 週間 1 スプリント● リリースは毎週

– 自社サービスではないのでどんどん出すという感じではない

– だが、常に最新の機能をリリースできる状態を保つ

● 今回はタスク管理などにはあまり触れずに開発者目線で

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

master

staging

devel

features

ブランチモデルリリース

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

ブランチモデル

● master ブランチ– 本番反映対象

● staging 系列ブランチ (例: staging-20150101-000000)

– 本番反映ごとに別ブランチ名で毎回作成● devel ブランチ

– リリース可能なものをマージ● features

– 開発ブランチ

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

ブランチモデル

● Git-flow のブランチモデル● devel ブランチは常にリリース可能な状態に保つ

● リリース済みの機能の緊急修正は master ブランチからブランチを切って行う

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

新機能開発、バグ修正

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

master

staging

devel

features

ブランチを作成して開発開始

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

pull request を作成

● 開発中に立てるかどうかは任意– コードレビュー時には必須

● 開発中の様子が見えやすい● 開発中のコードについて議論しやすい● Jenkins によるテストの結果の可視化

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

開発時の Jenkins の役割

● Push されるごとにライブラリ更新、JS minify– 必要な場合のみ– 結果をコミット

● Push されるごとにテストを実行– 失敗時には通知する– Slack、GH;E

● 動作確認のために開発用ホストにデプロイ (Docker 使用、後述)

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

Push されるごとにビルド実行

● Jenkins の GitHub Plugin● GH;E の Server Hook● 処理内容は script/jenkins.sh に記述

– Static ファイルの変換処理 → コミット、or– テスト実行 (Perl、JS)

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

GH;E のコミットへの通知

● Shell スクリプトの中に記述– ブクマなどでは通知用ジョブを下流に用意

curl -X POST -H "Authorization: token $token" \ https://github-enterprise.example.com/api/v3/repos/example/Example-Project/statuses/$git_head -d "{ \ \"state\": \"success\", \ \"target_url\": \"${BUILD_URL}\", \ \"description\": \"The build has succeeded.\" \ }"

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

Slack への通知

● Slack の Integrations● Jenkins の Slack Notification Plugin

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

良いところと課題

● ○ push したら自動でテスト実行● ○ 失敗時の通知がされる

– × Slack と GH;E だけなので弱い → XFD?– × GH;E への通知がビルド処理の中にある

● ○ ファイルの変更結果をコミット● × ファイル変更とテスト実行が同じ Shell ス

クリプトになっていて管理しづらい● ○ コマンド 1 つで確認用にデプロイ

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

レビューとマージ

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

開発が完了したらコードレビュー

● Pull request 上でコメントを残してやりとり● 問題がある箇所は修正・変更

– ここでの Jenkins の役割は開発時と同じ● レビュアにとってテスト結果が GH;E 上で確

認できるのが便利– テストに通っているかどうかすぐにわかる

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

レビュー後 devel ブランチにマージ

● Pull request のマージボタンでマージ● 先にコンフリクト解消が強制されるのでコン

フリクト解消ミスをしづらい● テスト失敗時にわかりやすい

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

master

staging

devel

features

レビュー後 devel ブランチにマージ

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

良いところ

● ○ レビュアがテスト結果を確認しやすい● ○ テストに落ちているのに気付かずマージ

ということがない– devel ブランチをリリース可能な状態に保てる

● ○ マージボタン強制によりコンフリクト解消のミスをしづらい

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

デプロイ

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

本番リリース用 pull request 作成

● Staging 系列のブランチを作成して master ブランチに向けた pull request を作成– ブランチ作成、pull request 作成をコマンド 1

つで実行● Staging 系列ブランチを staging 環境にデ

プロイして動作確認– デプロイは Capistrano 3

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

master

staging

devel

features

本番リリース用 pull request 作成

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

本番リリース用 pull request 作成

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

Staging の動作確認後にリリース

● 本番リリース用 pull request のマージボタンで master ブランチにマージ

● Capistrano 3 で本番デプロイ

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

master

staging

devel

features

Staging の動作確認後にリリース

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

良いところと課題

● ○ 本番リリース用 pull request をコマンド 1 つで作成できる

● ○ デプロイもコマンド 1 つ● × staging 環境へのデプロイが自動化され

ていない

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

まとめと今後

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

少年ジャンプルーキーの開発プロセス

● Jenkins、GH;E の活用、連携– テスト (インスペクション含) の自動実行でコー

ド品質を保つ– ファイル変更処理

● デプロイは少ないコマンドで完了– Jenkins は使っていない

● 継続的なソフトウェア進化の礎– 改善し続けることが大事

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

今後: Jenkins Workflow Plugin 検討

● 2014 年 12 月にバージョン 1.0 リリース● Scripted control flow

– Shell スクリプトに書いてあることを Workflow Plugin のスクリプトに置きかえる

● Pause and resume execution– ユーザーとのインタラクションの機能もあるので

デプロイ処理を Jenkins に乗せやすい

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

Docker コンテナによる確認環境と Jenkins開発中の機能を確認するための環境を準備する方法の紹介。

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

たとえばこんなこと

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

D

E

作品をお気に入りする機能を作るで!あれが云々これが云々や。

機能開発して

よっしゃ、作るで!……できたで!

Dほんなら次回リリースするで!

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

D

E

作品のお気に入り機能、ここがこうなってこうやと思ってたんやけどなー。

リリース直前に初めて動作確認

リリース前の動作確認や!!

E なんやて!!

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

なんてことはさすがにないと思うが

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

開発した機能の確認が遅れると困る

● 無駄な手戻り● 開発スピードの低下● 特に UI/UX 周り● 開発中の機能を確認できる環境は便利

– チーム内 : 動作を見ながら開発を進める– ステークホルダーによる確認

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

目的

開発中の機能の動作や UI/UX を確認するための Web アプリケー

ションを手軽に動かしたい

社内では devhost と呼んでいる

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

master

staging

devel

}featuresココが対象

対象とするブランチ

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

前提として

● 開発者自身はローカルホスト上でアプリケーションを動かして開発

● Devhost は誰のために?– チーム内のメンバー (非開発者・遠隔地)– チーム外

● → 社外からも見えるように (状況次第だが)● ブランチ名に対応するドメイン名● ストレージは開発用に 1 つ

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

https://{branch-name}.dev.example.com/

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

既存の方法 (はてなブックマークなど)

● 開発用サーバで複数アプリケーション起動● 別ポート番号を使用 (or Unix ドメインソケット)

● ポート番号解決 : Nginx 上の Lua で

https://{branch-name}.dev.example.com/ → {ポート 番号}

開発用 proxy

Nginx

開発用サーバー

Nginx

アプリケーション

アプリケーション

アプリケーションポート番号解決

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

課題

● 同じ環境を複数アプリケーションが使用するので面倒だったり問題が起こったり– ファイルシステム、ライブラリ等

● ブランチ名とポート番号の対応付けが面倒– ファイルを使って管理するなど

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

そこで Docker Engine の登場

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

Docker Engine とは?

● コンテナ型の仮想化技術– 環境を分離するという目的に適す

● ゲストの状態を Docker イメージとしてバージョン管理

● Dockerfile にビルド処理を記述して Docker イメージをビルド

● Docker イメージをもとに Docker コンテナ内でアプリケーションを動作させる

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

コンテナ型の仮想化

物理マシン

ハイパーバイザ

仮想マシン

ゲスト OS

● ユーザー空間を分けてリソースを制限する– ファイルシステム、プロセス、など

物理マシン

Kernel

ユーザー空間

ユーザー空間

コンテナ型の仮想化完全仮想化

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

Docker イメージとコンテナ

Dockerfile

Docker イメージ

docker build

Docker コンテナ

Docker コンテナdocker runコンテナが生成され中でプロセスが動く

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

Docker コンテナを用いた確認環境

● 開発用サーバで複数 Docker コンテナ起動● 別ポート番号を使用● ポート番号解決 : Docker API を使用

https://{branch-name}.dev.example.com/ → {ポート 番号}

開発用 proxy

Nginx

開発用サーバー

Proxy 用 Plackアプリケーション

Docker コンテナ

Docker コンテナ

Docker コンテナDocker API

ポート番号解決ポート番号解決

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

Docker API を用いたポート番号解決

● ホスト側のポート番号が適当に割り当て– コンテナ内の web アプリケーションは 80 番ポートをリッスン

– Docker コンテナは 80 番を EXPOSE● 各ブランチからイメージをビルドする際、ブラ

ンチ名に対応したタグをイメージに付ける● ホスト名からブランチ名を抽出 → Docker API により対応するタグ名のイメージのコンテナを探す → ポート番号取得

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

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];

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

Docker コンテナの生成

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

Dockerfile を準備して docker build

● ライブラリ等インストール → プロジェクトのファイルコピー → コマンド登録

FROM debian:stable# (略)# config/setup.sh は本番サーバー構築時にも使用される初期化スクリプト。COPY script/setup.sh /app/shared/script/setup.shRUN sh /app/shared/script/setup.sh# (略)

# SourceRUN mkdir -p /app/srcCOPY . /app/src# (略)

WORKDIR /app/srcEXPOSE 80CMD ["supervisord", "-c", "/app/src/config/docker/webapp/supervisord.conf"]

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

イメージビルドに時間がかかる問題

● debian:stable から最後までビルドすると 30 分程度かかる– apt-get や Perl のインストール– Perl ライブラリのインストール

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

イメージビルド時のキャッシュの活用

● Docker イメージのビルドにキャッシュが効く● デフォルトで有効● COPY すると (変更されてると) キャッシュ効

かない● プロジェクト全体を COPY する前に、初期化処理用のファイルだけを COPY– それらのファイルが変更されていなければ初期

化処理のキャッシュが有効に!

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

# config/setup.sh は本番サーバー構築時にも使用される# 初期化スクリプト。COPY script/setup.sh /app/shared/script/setup.shRUN sh /app/shared/script/setup.sh

# CPAN ModulesRUN mkdir -p /app/shared/cartonWORKDIR /app/shared/cartonCOPY cpanfile /app/shared/carton/cpanfileCOPY cpanfile.snapshot /app/shared/carton/cpanfile.snapshotRUN carton install --deployment

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

キャッシュ効果でビルド時間短縮!!

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

Jenkins 上でのビルドとデプロイ

● Jenkins 上で– docker build– docker rm -f : 同じブランチのコンテナを止める

– docker run● 実際のコマンドは rake タスクにしてある

– ブランチ名 → タグ名変換処理– 同じブランチの古いコンテナが動いてるか調査– Shell スクリプトより Ruby の方が書きやすい

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

Jenkins 上でのビルドとデプロイ

1. git clone

イメージ

2. docker build

コンテナ

3. docker rm / docker run

開発用サーバー

開発用サーバー内で完結しているので単純

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

ビルド開始方法

● 現在は手動でビルド開始– Jenkins API 叩く or Web UI から– 対象ブランチをパラメータで受け取り

● 本来は次のようにしたい– devel ブランチへの push で自動的にビルド– 既に devhost が立っているブランチへの push

で自動的にビルド

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

対象ブランチのパラメータ化

POST /job/{job-name}/buildWithParameters?branch_name={branch-name}

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

なぜ Jenkins でビルドするのか

● 同じ環境でビルド処理を行わせたい● ビルドの管理● 変遷

– Capistrano などで直接開発用サーバー上でビルド → 複数人が同時に使うと破滅

– Docker API を使う → キャッシュが効きづらくて困る

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

今後

● devel ブランチの自動デプロイ● Pull request との関連付けを強める

– コメントで新規 devhost 作成 (?)– close 時に自動で devhost 破棄– 破棄が結構面倒なので自動化したい

● ビルド後にコンテナ内でテストしてそれからデプロイ

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

小ネタ: 確認環境用の favicon

● ローカルホスト上の web アプリケーションや確認用の web アプリケーション

● 本番と確認用を間違えたりしてしまう● Favicon を変えることでタブで識別しやすく

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

小ネタ: 確認環境用の favicon

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

まとめ

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

はてなにおける Jenkins

● GH;E への push に応じたテスト自動実行や確認用ホストへのデプロイなど

● 開発プロセスの中でビルドやテストの実行を指揮する大切な役割を果たしている– 少年ジャンプルーキーでの例を紹介

● Jenkins で Docker ビルドしてデプロイするという仕組みで手軽に確認環境を用意

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

We are hiring!