LoginSignup
5
2

More than 5 years have passed since last update.

突撃!隣のリリースエンジニアリング〜Mackerelさんのお宅編〜

Posted at

はじめに

今作っているプロダクトに、ちゃちゃっとTravisCI環境を導入したくなりました。

そこでパクる参考にするため、すでにTravisCIを利用しているプロダクトとして
mackerel-agentのリリースエンジニアリング周りのソースを読んでみたのでメモを残しておきます。

対象ソース/扱う範囲

この記事では執筆時点のmackerel-agent最新バージョンであるv0.41.1を題材にしています。

取り上げる範囲としては、主にTravisCI周りだけです。
実際にはTravisCIだけでなくAppVeyorを使っていたり、表に出てこないバックエンドのプロセス(例えばChatOps用のボットとか)などがあると思いますので、ここで取り上げるプロセスはリリースエンジニアリングの一部のみとなります。

また、リリース周りはコードが陳腐化するのが早いですので、当記事を参考にする際は最新のソースも合わせて読むことをオススメします。

Let's read リリースエンジニアリング!

全体像

まずはTravisCIの設定ファイルである.travis.ymlから読んでみます。

以下のようなことを行うようになっていました。

  • lint/コード整形/テスト/カバレッジ測定/ビルドなど
  • ビルドした成果物をrpm/debにパッケージング(dockerを利用)
  • リリース用プルリクエストの作成
  • GitHub Releaseへのアップロード(ステージング/本番リリース)
  • 結果をSlackで通知

順番に見ていきます。

lint/コード整形/テスト/カバレッジ測定/ビルドなど

ビルド周り/テストなどは以下の記述がされています。
単純な記述なため、見るだけである程度処理の予測がつくかと思います。

.travis.yml(ビルド/テスト周り抜粋)
language: go
go:
- 1.7
script:
- make lint
- make cover
- test `gofmt -l . | wc -l` = 0
- make crossbuild
after_script:
- goveralls -coverprofile=.profile.cov

golang:1.7でビルドするために、language: gogo:の記述がされています。
script:にlintやカバレッジ測定などの実際のテスト/ビルド処理などが書かれています。

after_script:はカバレッジ測定用です。詳細は以下のサイトに載っていました。

参考:複数パッケージ構成のgolangのプロジェクトのカバレッジを測定しcoverallsに投稿する

ビルドした成果物をrpm/debにパッケージング(dockerを利用)

続いてrpm/debの作成です。.travis.ymlでは以下の部分です。

.travis.yml(パッケージング周り抜粋)
before_deploy:
- docker pull astj/mackerel-rpm-builder:c5
- docker pull astj/mackerel-rpm-builder:c7
- make rpm deb rpm-kcps deb-kcps rpm-stage deb-stage tgz
##以下デプロイ周りの処理が続く##

パッケージングの処理はbefore_deploy:以下に記述されています。
RPMのビルドで使うdockerイメージをpullした上でmake rpm deb(以下略)を実行するようになっています。

dockerイメージはrpmbuildコマンドをエントリーポイントとしたもので、これでrpmの作成を行なっています。debについてはdockerではなく直接debuildコマンドを実行しています。

なお、TravisCI上でdockerを利用するためには以下の記述が必要です。(もちろんmackerel-agentの.travis.ymlにも記載されています)

.travis.yml(dockerを使う設定抜粋)
sudo: required
services:
- docker

リリース用プルリクエストの作成

特定の名前(bump-version-x.y.z(x.y.zはバージョン番号))のブランチをGitHubへpushすることでリリース用のプルリクエストを自動生成するようになっています。

TravisCI上でGitHubの履歴を参照し、前回のリリース以降にマージしたプルリクエストの情報などを以下のCHANGELOGに埋め込む処理を行なっています。

これらのファイルの変更をpushされたbump-version-x.y.zブランチにコミットした上で
github用のCLIツールhubを用いてプルリクエストを作成しています。

.travis.ymlでは以下の部分です。
色々細かなことをやっているため、コメント(風)の説明を入れてみました。

.travis.yml(リリース用PR作成部分の抜粋)
before_deploy:
##省略:前述のパッケージング処理##

# GitHubの操作用コマンドのソース取得 & ビルド
- go get github.com/aktau/github-release
- mkdir -p ~/bin
- git clone https://github.com/github/hub.git && cd hub && script/build -o ~/bin/hub && cd ..

# CHANGELOGの作成などで利用するために、ビルド対象以外のブランチの情報も取得
- echo $TRAVIS_BRANCH
- git config --add remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
- git fetch
- git checkout master || git checkout -b master origin/master
- git checkout $TRAVIS_BRANCH
- git fetch --depth=1000
- git fetch --tags --depth=1000 || true

deploy:

## 省略:GitHub Releaseへのアップロード処理(後述します)

# リリース用プルリクエストの作成処理
- provider: script
  script: _tools/releng --task=create-pullrequest --current-branch=$TRAVIS_BRANCH -v
  skip_cleanup: true
  on:
    all_branches: true
    condition: "$TRAVIS_BRANCH =~ ^bump-version-.*$"

before_deploy:hubコマンドのインストールなどの準備作業を行った上で、
deploy:に書かれた作業を行うようになっています。

deploy:ではprovider: scriptと記載することで、任意のスクリプトファイルを実行するようにしています。ここでは_tools/relengというスクリプトを実行しています。
また、on:以下に条件を書いておくことで、bump-version-x.y.zという名前のブランチの場合のみ処理が行われるように制限を行なっています。

デプロイ用スクリプト_tools/releng

プルリクエスト作成やGitHub Releaseへのアップロードを行うためのperlで書かれたスクリプトです。
hubコマンドやgitコマンド、github-releaseコマンドを呼び出しています。

ポイント

CHANGELOG変更分をcommit/pushしたりプルリクエストを作成するにはGitHubのアクセストークンが必要です。
アクセストークンは.travis.ymlに暗号化された環境変数として設定しておくことでスクリプトに渡しています。

.travis.yml(GitHubアクセストークン(など)の環境変数設定部)
env:
  global:
  - secure: "B34YsRebWxyx/UAHNAL5YWOgx2RE13TVfDC8FCCc7gAlogJcyAcPnC88fe8ECChHQC3GNnsHSi+GqgxTxzfoVkV+LUAFgHWbcF5O4O/4qHztKj7//72RwO+gXVr4U1Laz45bBr2r68XW0llj5tIlaEYxROJNLSAVDE4yDzmAHgc="

この値はTravisCIのCLIツールであるtravisコマンドで作成できるものです。
(今回はtravisコマンドについての説明は割愛)

この設定を行っておくことで、deployスクリプトの中から環境変数を参照可能です。
(以下の例では環境変数GITHUB_TOKEN)として渡しています。

_tools/relengのトークン利用部
git_without_stderr qw/push -u/, "https://$ENV{GITHUB_TOKEN}\@github.com/$REPO_NAME.git";

なお、GitHubのトークンは漏れるとやばい情報です。
(今回の場合、このトークンがあればリポジトリにpushできちゃいます、、怖い。。。)

トークン利用時にTravisCIのログに表示されないように、標準出力/エラーのリダイレクトなど適切な処理を行うことを忘れないようにしましょう。

参考:Travis CIのテストの中でGitHubのレポジトリへpushする

GitHub Releaseへのアップロード(ステージング/本番リリース)

リリース用のプルリクエストがマージされたらGitHub Releaseへバイナリやrpm/debなどのパッケージファイルがアップロードされます。

これは.travis.ymlの以下の記述で実現しています。

.travis.yml(GitHub_Releaseへのアップロード部分抜粋)
deploy:
- provider: script
  script: _tools/releng --task=upload-to-github-release -v && _tools/releng --task=upload-master-to-github-release -v
  skip_cleanup: true
  on:
    branch: master

on:branch: masterという記述を行なっていますので、masterブランチに変更があった場合にこの処理が行われます。
運用ルールとしてmasterへの直接コミットを禁止しておくことで、プルリクエストのマージ時にのみこの処理が行われることになります。

ここでのデプロイスクリプトの動きとしては、

  • 1) GitHub上に現在のバージョンのリリースがなければ作成 & ファイルアップロード
  • 2) stagingリリースへファイルアップロード

となっています。
新バージョンのリリース以外でmasterにマージされたコミットはstagingリリースにアップロードされていくということですね。

slackへの通知

特に説明することはないでしょう。見たままです。

.travis.yml(slack通知設定部分の抜粋)
notifications:
  slack:
    secure: n9Hs5rIlb6MuFVsRp46ykd+CptnE3boI7Q9mNLuHwz77IQ/2mpUmOyBRDeW3BA2EXa4WEYAXu8q7/b7zVV+c+RcPdz8/h9N9EBrHUVeIkCP/Nyp+aUA8GvLNjGuxYC7nov3L+9GHBFXKX8FaV2lZ1/Eeb1Ovbtv6Oi39xNkHqTQ=

おまけ:バイナリへのバージョン情報埋め込み

デプロイで利用しているブランチ名bump-version-x.y.zを利用して、goのバイナリのビルド時にバージョン情報を埋め込む処理をしてたりします。

これは、

  • Makefile内でgitのログを検索&加工してバージョン情報を取得
  • 取得したバージョンをgo build時のオプション-ldflagsに指定

することで実現しています。

Makefile抜粋
CURRENT_VERSION = $(shell git log --merges --oneline | perl -ne 'if(m/^.+Merge pull request \#[0-9]+ from .+\/bump-version-([0-9\.]+)/){print $$1;exit}')


BUILD_LDFLAGS = "\
      -X github.com/mackerelio/mackerel-agent/version.GITCOMMIT=`git rev-parse --short HEAD` \
      -X github.com/mackerelio/mackerel-agent/version.VERSION=$(CURRENT_VERSION) \
      -X github.com/mackerelio/mackerel-agent/config.agentName=$(MACKEREL_AGENT_NAME) \
      -X github.com/mackerelio/mackerel-agent/config.apibase=$(MACKEREL_API_BASE)"

定義を1箇所にまとめるテクニックの好例ですね。

終わりに

ざっと.travis.ymlを中心に見てきました。

リリースプロセスとしてはおそらくバージョンアップ時のブランチ(bump-version-x.y.z)作成などにボットなどを利用してChatOpsしてたりするのだと思います。

リリースエンジニアリングには各開発者(会社/コミュニティ)の個性が出る部分だと思いますので、
読んでいくのは楽しいものです。
機会があれば別のプロダクトについても読んでみたいと思います。

以上です。Enjoy!

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2