For the complete documentation index, see llms.txt. This page is also available as Markdown.

リリース・デプロイ戦略を支える技術

ここでは Kubernetes 上で起動する server や worker の deploy 戦略について説明します。 Wantedly における Git 及び GitHub の運用方法が前提となるので事前に Git の慣習 を読んでおくと良いでしょう。

デプロイ基盤

GitHub Flow の実現方法

各 repository で CI/CD で下の2つのことを行うことで GitHub Flow を実現しています。

  • 全 branch: Docker image の build (kube ci-build)

  • main (master): Docker image の deploy (kube <env> deploy)

ここで ci-build は commit hash を tag にもつ docker image を作成して registry に保管し、 deploy コマンドが Kubernetes の Deployment に対する変更を反映することで rolling で deploy されます。

いわゆる CIOps という Push 型のデプロイです。

Docker image 以外の更新、つまり Kubernetes Manifest のデプロイについては Argo CD による GitOps という Pull 型のデプロイを採用しています。

GitHub Flow を CIOps (Push 型) と GitOps (Pull 型) の二重構造で実現する全体像

Rolling Deploy

Rolling deploy では新旧2つのアプリケーションバージョンを一部ずつ置き換えていきます。 このため、アプリケーションにもよりますが最大で数分程度複数のバージョンが共存する時間ができることになるため、 すべての deploy は後方互換性をもたせる必要があります。 一例としてフロントエンドとサーバーサイドのコードを 1 つのコードベースで管理している microservice (wantedly/wantedly, wantedly/perk など) では API 追加とその API に依存する frontend は先に API のみを merge する必要があります。また逆に機能を落とす場合は先にフロントエンドからの依存がない状態を merge 仕切ってから API を落とす pull request を merge する必要があります。

Rolling Deploy における Pod の段階的置換と共存期間

Kubernetes Manifest 管理

kube-generate.yaml から Argo CD を経由して Cluster に反映されるまでの全体像

Argo CD による GitOps

Kubernetes Manifest は Argo CD を導入して GitOps という Pull 型のデプロイを行っています。

もともと Wantedly では Docker image の deploy を CICD で行っていましたが、Deployment 以外の Kubernetes manifest は長らく手動での apply になっていました。 そのため、以下のような課題・問題がありました。

  • リリースフローの自動化・高速化・簡易化を行い、インフラチーム以外でも Kubernetes Manifest の管理を可能にすることで開発・リリースの速度を早めたい

  • apply 忘れなどで repository と実際に apply されている manifest が異なり、Kubernetes Cluster のメンテナンスや Upgrade のブロックになっていた

  • apply 忘れなどで repository と実際に apply されている manifest が異なり、リリース時にアプリケーションエラーを引き起こすインシデントになった

そこで Argo CD による GitOps を導入 (internal) し、特に kubernetes manifest の継続的なデプロイの自動化をゴールとして、これらの課題を解決しています。

ただし先述したとおり、アプリケーションコンテナのデプロイ は CICD で Kubernetes Deployment に対して変更を加えて Rolling Deploy を行っているため、docker image tag は GitOps の対象外となっています。 これは

  • 課題に対して docker image tag の GitOps は一旦スコープアウトできる

  • 障害対応時には kube <env> deploy <commit hash> コマンドで緊急切り戻しを行っているため、このフローのアジリティを壊したくなかった

といった背景がありました。

今後、docker image tag も含めて CIOps から GitOps への移行を検討するなど、さらなるデプロイ戦略の改善を進めています。

Kubernetes Manifest の自動生成・更新

GitOps に加えて、Wantedly の microservice のための Kubernetes Manifest を自動生成して継続的に更新する仕組みがあります。 これにより、その repository に必要な Deployment, HPA, Service, PDB といった Kubernetes Resource を、Wantedly の microservice における推奨設定込みで用意できます。

generator は autoscale (Deployment + HPA + Service + PDB) のほかに ingress, cronjob, worker など複数用意されており、kube generate のサブコマンドから一覧を確認できます。

kube-generate.yaml による宣言的な管理

以前は kube generate <subcommand> を都度手元で実行したり、生成コマンドを列挙したシェルスクリプトを repository に置くことで manifest を生成していました。 この方式では「現在どの generator にどの設定で manifest が作られているのか」がコマンド履歴やスクリプトを読まないとわからず、再生成のたびに手元での操作も必要でした。

そこで現在は、生成したい manifest の内容を repository ルートに置く kube-generate.yaml に宣言的に記述する方式を推奨しています。 たとえば次のような内容になります。

generates: 配下の各項目が利用する generator とその設定に対応しています。 この kube-generate.yaml をもとに kube generate --update を実行することで Kubernetes manifest 一式が再生成されます。 新たに generator を追加したい場合は kube generate --save <generator> を実行すると kube-generate.yaml に対応する項目が自動で追記されます。

kube generate がサポートしていない設定を加えたいときは次のいずれかの方法で対応します。

  • kube generate の generator 実装そのものを拡張する

  • kube-generate.yaml 上で patches を指定し生成結果に変更を加える

  • 手動編集した manifest を kubernetes/ ディレクトリ以下に追加する。 metadata.annotationswantedly.com/generated-by: manual を付与しておくと自動再生成の対象から除外されます

継続的な再生成

kube generate のテンプレートは kube のバージョンアップに伴って更新されていくため、過去に生成した manifest が古いままにならないよう継続的に再生成する仕組みを用意しています。 Renovate のように最新の kube バージョンを検知して kube generate --update を実行し、差分があれば各 repository に manifest 更新の Pull Request を自動で作成します。 詳しく知りたい方はこちらも見てみてください。継続的な manifest 更新の取り組み (internal)

FeatureFlag

基本的にリリースブランチを持たない我々の開発手法ではコンフリクトを避けるためにコンスタントに main branch (master branch) へ merge していくことが重要です。 しかしながら main branch (master branch) で merge されると自動で deploy がなされるため、場合によっては変更をユーザーに見せたくないこともあります。 このような場合に FeatureFlag が有用です。 FeatureFlag は boolean, string のいずれかを返す method の返り値を request ごとに任意の値に変更できる Wantedly の社内基盤です。 値の変更を許可しておきたい method を事前に FeatureFlag の library で wrap しておくと Chrome Extension (internal) から override ができるようになります。 これを用いることでユーザーには機能を隠しておきつつ、qa 環境では簡単にその機能を顕在化させることができます。

FeatureFlag の override は QA/Sandbox では Chrome Extension / Kubefork から行えるが本番では無効化される

Override 宣言のやり方

まず override できる method を指定する方法を示します。 現在 Rails と React がサポートされていますがそれ以外のフレームワークや言語に対応要望がある場合は Infra Squad に相談してください。

Rails

最新 version の servicex が install されていることを確認してください。

※Rails の FeatureFlag 実装は本番環境では override されないことに注意が必要です。 実装参照(internal)

ただし本番環境でも FeatureFlag を使いたいケースは存在するため、実現に向けて検討中の段階となっています。 Issue 参照(internal)

使用したいモチベーションが冒頭の「コンスタントに main branch (master branch) へ merge していくこと」だけならば 実装としては本番環境かどうかは予め環境変数で弾いておき、その上で Feature Flag の制御をするのがおすすめです。 こうすることで QA, Sandbox ではその制御を dev tool から flag を override して確かめることが可能です。

React

Override のやり方

Chrome Extension

上記の方法で override 可能にした method は Chrome Extension (internal) から override できます。

Chrome Extension の popup を開いた表示

qa 環境にアクセスして Chrome Extension の popup を開くと response の render に使われた flag の一覧が表示されます。 ここで変更したい flag の override を値を更新してページをリロードすることでサーバーの挙動を override することができるためリリース前の機能などを試すことができます。

Kubefork

より高頻度に確認したい場合は、特定の Flag を有効にしたサーバーを別の URL で serve することができます。 具体例として下のような状況が実現できます。

  • 新しいデザインの LP を出すかどうかを new-lp という Flag で提供

  • https://new-lp.qa.wantedly.com のような URL を作成

  • ここにアクセスすると任意のブラウザにおいて Chrome Extension なしで new-lp が有効になっているものとして動作する

エンジニアチーム外の人にテストをお願いしたいときには特に便利です。

詳しい利用方法については fork のドキュメント(internal) の「特定の FeatureFlag が有効にしたものをテストしたい」のセクションを参照してください。

Pull Request Preview

上記のように FeatureFlag を使うことでリリースブランチを作らないようにすることが基本方針です。 しかしながら依存 Library の upgrade やアプリケーションの構成の変更などどうしてもリリースブランチを作る必要があることもあるでしょう。 こういったケースでは Pull Request Preview が便利です。 任意の Pull Request において /preview <env> とコメントすると次の図のように URL がコメントされるためここにアクセスするだけで preview が実現できます。

Pull Request Preview の例

ブランチに更新があると追従されるため、数週間以上に渡ってリリースブランチを維持しなくてはいけないときに特に有効です。 この機能のバックエンドは マイクロサービスでもポチポチ確認するための Kubefork であるため、 ユーザーフェイシングでないマイクロサービスでも利用可能です。 主要な repository はサポートされていますが自分の管理する repository が対応しているかについては Infra Squad に問い合わせてください。

Migration

GitHub Flow では main branch (master branch) に存在する commit はすべて deploy 可能であるべきです。 もちろんこれを完全に保証することは不可能ですが、自動デプロイを行っているため少なくとも最新の commit が deploy されて困る状態は許容できません。 したがって、データベースの migration に依存する commit の merge は migration のあとに行われる必要があります。

そこでこれを保証する CI として pending-migration-checker(internal) があります。

pending-migration-checker による merge ブロックと migration 実行後の再 check フロー
Pending Migration Checker の例

この check が落ちている場合は migration が必要です。 migration を kube prod sh などで実行して、/check migration とコメントすることで再度 check が実行されます。 詳しい設定方法などは上記の repository のリンク先を参照してください。

話を聞きに行きたい

もっと知りたい

最終更新