タグ付けデプロイの思想的裏付け

こんにちは、皆さん

PHP勉強会の第126回にて、[タグ付けデプロイの話をした](https://speakerdeck.com/niisantokyo/tagufu-kedepuroifalsehua)のですが、十分に思想的な背景を説明できていなかったので、この場で説明をしようかと思います。

# 前提
勉強会で話した内容などについては、以下にまとめておきます。

## タグ付けとは
`git tag` を使って特定のコミットに対して目印をつける行為を指しています。

## タグとリリース
`git tag`自体はただ目印をつけるだけですが、その目印に意味を付加することができます。

GitHubを常用している方なら、すでにご存知かと思いますが、GitHubではリリースの概念があり、それは特定のコミットに対し、リリース用のタグ、例えばバージョン番号 ( vx.x.x )をつけることでなされます。
GitHubのプロジェクト内でreleaseを選択すると、リリースリストとしてのタグの一覧や、タグ付けのUIにアクセスすることができます。

これは同じようなgitのホスティングサービスであるGitLabでも似たような傾向があり、タグにつけるメッセージの他に、リリースノートというエクストラなメッセージを指定できるようになっています。

このようにタグをつけることで、そのコミットをリリースしたとみなそうという試みが、すでに存在しています。

## タグ付けデプロイ
タグをつけることをデプロイのスイッチにしようという試みです。

先に述べたように、タグをつけることをリリースとみなすことができるわけですが、サービスにおけるリリースとは、すなわちデプロイのことです。
そんなわけで、「タグをつけたらデプロイする」というフローが出来上がるわけです。

## タグ付けとCI
タグをつけっぱなしでデプロイを忘れてしまっては意味がありませんので、タグ付けをトリガーとしてCIを起動させ、自動的にデプロイする機構があるのが望ましいと考えています。
幸いなことに、最近よく使われるカジュアルなCIであれば、タグ付けを感知できますので、安心してタグ付けデプロイの機構を構築できます。

Travis CI
https://docs.travis-ci.com/user/customizing-the-build#Safelisting-or-blocklisting-branches
https://docs.travis-ci.com/user/customizing-the-build#Using-regular-expressions

Circle CI
https://circleci.com/docs/2.0/configuration-reference/#filters-1

GitLab CI
https://docs.gitlab.com/ee/ci/yaml/#only-and-except-simplified

# デプロイにおける思想 ( 課題 )
では、今回のタグ付けデプロイについて何が重要なのかについて述べていきます。
現在の開発スタイルは、toBのシステムであることもあって、まずステージングにシステムをデプロイし、動作確認やQA確認を済ませた後、本番環境にデプロイするという、割とオーソドックスなものとなっています。
その中で、最も気にしていた課題があって、これを解決しようとしてたどり着いたのが、タグ付けによるデプロイです。
おそらく、何人も先駆者はおられるでしょうが、それでもこれにたどり着いたときは感動すら覚えたものです。

## ステージングと本番環境の同一性問題
デプロイにおける関心事として、私の中ではこれが最大のものです。
せっかくステージングでQA確認まで済ませているというのに、肝心の本番がステージングと乖離していたら元も子もないわけです。

私の保守しているシステムは、コンテナにより運用されています。
コンテナのもとになるコンテナイメージですが、極稀に変な状態のものができることがあって、その状態で本番にデプロイなどされようものなら、目も当てられない事故が起こるかもしれません。
よって、本番にデプロイされるコンテナのイメージは、ステージングでQAを済ませた安全なイメージでなければならないのです。

## github-flow
gitを使った開発のフローに、github-flowというものがあります。
https://gist.github.com/Gab-km/3705015
https://qiita.com/tbpgr/items/4ff76ef35c4ff0ec8314

図などは、上述したリンクの方を参照いただくのが良いかと思いますが、簡単に内容を説明しますと

1. 新しい機能やバグ修正をするためのブランチを master からきる
2. ブランチ上で追加・修正をしたら、masterに向けてプルリクエスト (GitLabではマージリクエスト ) を出す。
3. レビューの上、問題なければmasterにマージする
4. master ブランチは常にデプロイ可能な状態になる

という感じです。

いろいろとバックグラウンドの思想はあるのでしょうが、個人的にはとても素直な開発方法なので、私はよく使用しています。
git-flowという、よりしっかりした開発方法もあるのですが、しっかりしすぎていて管理が面倒なので、個人的には役割分担がすごくしっかりしたプロジェクト以外では、使いにくいかなっていう印象です。

ところで、github-flowの考え方の中に、「master ブランチは常にデプロイ可能」というものがあります。
これは最新の価値を常にユーザーに届けたいという想いが込められていると思うのですが、前述した「ステージングと本番の同一性」において、少々問題があります。

## github-flow と 同一性
github-flowにおいて、ステージングの概念は明確にはありませんが、レビュー中に動作確認するための環境を用意するかもしれないので、その環境をレビュー環境として考えてみることにします。
ブランチのコミット状況と各環境へのデプロイの状況はこんな感じです。

![githubflow.png](https://qiita-image-store.s3.amazonaws.com/0/102182/19f87718-d241-d303-ad3f-ab028f39d263.png)

一見すると問題なさそうです。
しかし、トピックブランチがmasterにマージされるとき、(fast-forwardが発生しない限り)マージコミットが作成されます。
つまり、トピックブランチの先頭とマージ後のmasterはコミットハッシュが違うということです。
他のトピックなどがあり、masterブランチもまた成長する場合を考えると、デプロイされたレビュー環境と本番環境は一致したものであるとは言えません。

# タグ付けによる同一性の担保
github-flowは素直な開発手法なので、使いたいところですが、上述した同一性の難が発生してしまうため、そのままでは使えません[^1]でした。
そこで、タグを付けるというワンステップを追加することで、QA確認されたものを確実に本番環境にデプロイできます。
からくりは至って単純で、

1. master は常にステージング環境にデプロイされる
2. タグを付けられたmaster上のコミットは、本番環境にデプロイされる

という、仕組みを作ればよいだけです。
コードを直接でプロイする仕組みであれば、本番環境上でタグの付いたコミットにリビジョンを動かしてやれば良いでしょう。
私がやっているコンテナデプロイの方法であれば、ステージングで使ったイメージを、そのまま本番に適用すればいいだけです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/102182/4cf5b7e7-c2d4-2d59-85ca-2ffd17319482.png)


と、このようにして、タグ付けデプロイによって、確認用のステージングと本番の同一性を保証しているわけです。
github-flow にワンステップ追加するだけと、非常に簡単ですので、環境の同一性に困っている方は、試してみるといいかもしれません。

# まとめ
タグ付けデプロイの思想的な裏付けとして、環境の同一性を担保したいという考え方を紹介しました。
前職からステージングと本番のこの問題に悩んできたのですが、タグ付けするだけで簡単にその悩みを解消できたのですから、感動モノでした。
また、今回の考察を通して、github-flow の考え方が、結構応用が効くものではないかというように思うようになりました。
よく使われているやり方には、それなりの意味があるんだなぁと当たり前の感想を得たところで、今回はこんなところにしようかと思います。

[^1]: もちろん、QA確認が不要、つまり迅速なデプロイによるリスクがそれほど高くなければ、github-flowのままで良いと思います。勘定系のシステムでやると爆死するかもしれませんが、ブログサービス程度であれば大丈夫じゃないだろうか、みたいな感じでしょうか