こんにちは、menu事業部エンジニアインターンの原です。7-8月の2ヶ月間、menuのマイクロサービスチームでインターンをさせていただいていました。
今回は、自分がその間に行ったタスクの一つであるプログレッシブデリバリーの導入についてご紹介したいと思います。
プログレッシブデリバリー is 何
デリバリーと名づけられているため特定の継続的デリバリーの手法のように思えますが、モダンなソフトウェアのリリースフローへの推奨されるエンジニアリングプラクティス、と形容したほうが的確かなと思います(SREのアイデアに構造的には近いかもしれません)。
ソフトウェアの要件によって取られる手法は様々なのでこれといった明確な手法は存在しませんが、カナリアリリースにオブザーバビリティの要素を判断材料とする自動ロールバックの機能を組み合わせたものがよく例としてあげられます。その他にも、フィーチャーフラグやカオスエンジニアリングなども内包する概念です。
技術構成
プログレッシブデリバリーを実現するにあたり、Argo Rollouts, Istioなどのカスタムリソースを利用しました。
Argo Rollouts
ソフトウェアのリリース手法には様々な手法が存在しますが、menuのような常に稼働していることが要件とされるSaaSではリリースのたびにダウンタイムを生むようなことは許容できません。こういったニーズに対応するため、ダウンタイムを発生させないリリース手法としてBlue/Greenデプロイやカナリアリリースなどの手法が存在します。
Argo Rolloutsはそういったダウンタイム無しのリリース手法をKubernetesで実現するためのOSSです。Argo CDなどで有名なArgoファミリーのソフトウェアですが、Argo CDとは独立して動かすことができます。
Rollout
ブルーグリーンデプロイやカナリアリリースをKubernetes上で可能とするカスタムリソースです。デプロイの自動分析・ロールバックやトラフィック制御を行ってくれます。Deploymentの代替/進化版のリソースといった位置づけです。
AnalysisTemplate
Rolloutでデプロイ中の新しいアプリケーションバージョンが正常かどうかを検証するための分析テンプレートです。この設定を元にAnalysisRunという分析が設定したタイミングで走ります。監視するメトリクスや、どのような条件(例: エラーレートが1%未満)を満たせば成功と見なすかなどをこのリソースで定義します。
Prometheus, Datadog, New Relicなどにクエリを投げたりJobを実行したりして分析を行うことが可能です。menuではGoogle CloudのマネージドPrometheusを利用しているため、そちらからメトリクスを引き出す形で構成しました。
Istio
Istioは主に2つの用途で利用されています。
VirtualService
サービスメッシュ内のトラフィックルーティングを制御するための中心的なリソースです。トラフィックの重みづけ、タイムアウト、フォールトインジェクションなど色々できます。
プログレッシブデリバリーを実装するにあたり、ヘッダベースのルーティングを行うのに利用しています。
Istio Standard Metrics
上に説明したAnalysisTemplateで分析するメトリクスとして、Istio Standard Metricsのistio_requests_totalを利用しており、レスポンスのステータスコードをもとにエラー検知を行っています。
変更前
変更前のリリースフローはシンプルです。以下の図のようにBlue/Greenを用いてダウンタイムなしのリリースを実現させています。
利用ユーザーへの影響を与えないという要件を満たすリリース方式ではあるのですが、リリースに何か問題があった際の堅牢性を高めたいということで以下のような変更を加えました。
変更後
Istio VirtualServiceのヘッダベースルーティングを用いた検証リクエストを投げられる機能とメトリクスを使った自動ロールバック機能を追加しました。
想定するリリースシナリオとしては以下の通りです。
-
通常の状態
-
変更がマージされ、コンテナがCIによってビルドされる また、CIがマニフェストリポジトリのコンテナイメージのハッシュを書き換える
-
Argo CDでマニフェストを同期する
-
RolloutをPromoteする
-
新しいイメージハッシュのReplicaSetが立ち上がる ここでリリースは一時停止状態に入ります
- この時点では新旧バージョン両方立ち上がっている
- リリース検証用のカスタムヘッダの付与されたリクエストのみ新バージョンへと割り振られる
- これを使いリリース担当者が新バージョンの挙動に問題がないかチェックすることが可能です
-
リリース担当者がArgo CD上でRolloutをResumeしリリースを続行する
- この時点で全てのトラフィックが新バージョンへと割り振られます
-
メトリクスを利用して新バージョンの挙動が問題ないかのチェックが実行される 失敗した場合はトラフィックは再度旧バージョンへと切り戻される
-
問題なければリリース完了
-
失敗時には通常トラフィックは旧バージョンへと切り戻されます。また、新バージョンはスケールダウンされず保持されるので、リリース担当者は何が問題だったのかをリクエストを投げて検証することが可能です。
以下参考までに主要リソースのmanifestです。
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: grpc-server
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: grpc-server
strategy:
blueGreen:
activeService: service
previewService: service-preview
postPromotionAnalysis:
templates:
- templateName: success-rate
args:
- name: service-name
value: service.example.svc.cluster.local
autoPromotionEnabled: false
scaleDownDelaySeconds: 300
abortScaleDownDelaySeconds: 30
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 2m
count: 5
successCondition: result[0] >= 0.95
failureLimit: 3
provider:
prometheus:
address: http://frontend.gmp-proxy.svc.cluster.local:9090
timeout: 40
# サービスのレスポンスの正常率を計算
# リクエストがない場合(割合がNaNになる)場合は正常率を1とする
query: |
(
sum(irate(istio_requests_total{reporter="destination",destination_service="{{args.service-name}}",response_code!~"5.."}[2m]))
/
sum(irate(istio_requests_total{reporter="destination",destination_service="{{args.service-name}}"}[2m]))
> 0
)
or vector(1)
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: virtual-service
namespace: istio-gateway
spec:
hosts:
- service.example.svc.cluster.local
- service-preview.example.svc.cluster.local
gateways:
- istio-gateway/istio-gateway
- mesh
http:
# リクエストが検証用ヘッダを含む場合previewへルーティングする
- route:
- destination:
host: service-preview.example.svc.cluster.local
port:
number: 5050
match:
- headers:
x-release-tester:
regex: ".*"
# それ以外の場合activeへルーティングする
- route:
- destination:
host: service.example.svc.cluster.local
port:
number: 5050
将来的な改善の余地
現状ではpreviewの検証は手動で行われるようになっていますが、将来的には自動E2Eテスト&リリース前の自動分析(上の図ではリリース後にAnalysisRunを実行していますがリリース前に差し込むことも可能です)を組み込むことで、よりリリースの堅牢性を高めることができ、ユーザーへの影響も抑えられる構成にできるかな、など構想しています。
また、現在はマネージドPrometheusへの認証のためGoogle Cloudの提供する認証プロキシ
(上の図でのgmp-proxy)を立てているのですが、Argo RolloutsでGoogle Managed PrometheusをサポートするPRが出されているので将来的にはダイレクトに認証できるようになりそうです。
終わりに
いかがだったでしょうか?自分は元々ダウンタイムなど全く気にせず自宅でKubernetesクラスターを運用していたのですが、今回のインターンを通して多くの知見が得られ、色々と改善のアイデアが浮かんできて楽しかったです(インターンが終わったら練り直そうと思います)。
リリースの堅牢性はサービスの改善サイクルのスピードアップに欠かせないものですので、今後もより良い改善の方法を模索していこうと思います。
▼新卒エンジニア研修のご紹介
レアゾン・ホールディングスでは、2025年新卒エンジニア研修にて「個のスキル」と「チーム開発力」の両立を重視した育成に取り組んでいます。 実際の研修の様子や、若手エンジニアの成長ストーリーは以下の記事で詳しくご紹介していますので、ぜひご覧ください!
▼採用情報
レアゾン・ホールディングスは、「世界一の企業へ」というビジョンを掲げ、「新しい"当たり前"を作り続ける」というミッションを推進しています。 現在、エンジニア採用を積極的に行っておりますので、ご興味をお持ちいただけましたら、ぜひ下記リンクからご応募ください。








