意図しないデプロイ

山下慶将氏(以下、山下):デプロイの問題は、Spinnakerが多くのデプロイ手法をサポートすること、そしてそれらを適切に選ぶことによって、ある程度は改善できると思います。それによって、安全なリリースフローを設計できるようになるのではないかなと思います。安全なデプロイだと、カナリアデプロイなどの手法があることを紹介しました。

しかしこれらのシステムは完全に信頼はできなくて、意図しないデプロイが発生してしまうケースもあると思います。

CI/CD、継続的インテグレーション、継続的デリバリーの基本的な考えとしては、小さなリリース単位、デプロイ単位をより頻繁に高速にデプロイすることです。そのため、それをより発展させた自動デプロイといったような、例えばContainer RegistryにDockerイメージなどが作成された時に自動でデプロイする機能などが、CI/CDツールにサポートされていることが非常に多いです。

SpinnakerでもAutomeated Triggersといって、今回の例だとContainer Registryのイベントを基に自動でパイプラインをトリガーして、GKEクラスタにデプロイすることを自動的に行う機能があります。しかしこれらの機能を完全に信頼していいかは別問題だと思っています。

例えば、設定ミスなどによって意図しないデプロイ、開発段階の機能、リリース前の機能が意図せずデプロイされてしまうリスクも存在しています。そのようなときに、SpinnakerのManual Judgmentというステージを設けることによって、意図しないデプロイを防げます。

Manual Judgmentの使い方

この機能は、実際にパイプラインがトリガーされたときに、それ以降の処理を行うかどうか。一般的には、そのあとデプロイするかどうかを判定するステージを設けられます。このようにGUI上で、StopかContinueかを入力する必要があります。ここでContinueを選ぶと、それ以降のパイプラインの処理、デプロイができるようになります。

Stopを選ぶと、これ以降のパイプラインの処理は行われずデプロイされません。なので意図せず勝手にパイプラインをトリガーしてしまったときも、このステージを挟むことによってストップできるようになります。Tipsとして、このManual Judgment機能をプロダクションでは必須にすることがおすすめです。

プロダクションではContinueだったりStopだったり、人間が承認するステージを必ず設けることによって、意図しないデプロイを防げます。

また、デベロップメント環境や他のテスト環境、組織によると思いますが、開発サイクルを回すことをベースに使っている環境では、Manual Judgment機能を使わないでおくことによって、GitHubのPR上でマージされた時や、Container Registryにイメージがプッシュされた時などを基に自動でデプロイして、開発環境などを同期できるようになります。

これによって開発サイクルを非常に高速に回せるので、プロダクションでは有効、デベロップメントでは無効にすることがおすすめできるのではないかなと思っています。

ここまでで、アプリケーションをデプロイすることについて、いくつかのリスクを紹介しました。それに対して、Spinnakerが提供するデプロイ手法を選定することによって、よりリスクの低いデプロイができるようになります。Manual Judgmentのステージを設けることで、意図しないデプロイを未然に防ぐこともできます。

また、機能をプロダクションでは有効にする、デベロップメント環境などでは無効にするといったプラクティスをすることで、開発速度を損なうことなく機能を使えるようになります。

パイプラインのベストプラクティス

次に、パイプラインのベストプラクティスについて紹介したいと思います。Spinnakerではパイプラインを作成することでデプロイを行うと紹介しましたが、それについていくつか問題点があります。1つはマイクロサービスごとによって、デプロイの質を担保するのが難しい点です。

マイクロサービスアーキテクチャでは、「各マイクロサービスが自律的に開発サイクルを回していく」という理念に根ざしています。そのため、組織全体でテストエンジニアだったりリリースエンジニアを特別に設けることなく、各マイクロサービスのデベロッパーが開発からリリースまで行う責任を担っています。

しかし、それぞれのチームが自律してデプロイ、リリースまで行うことによって、そのデプロイの質にいろいろな形態が出てしまいます。例えばTeamAがカナリアデプロイをしていて、TeamEがRed/Blackデプロイをしていると、そもそもこの2つに違いが出てしまいます。ひどい場合だと、TeamDがリリースフローに沿わないデプロイを勝手にしていたり。組織全体で見ていないので、これらを担保するのは非常に難しいです。

それぞれのマイクロサービスにデプロイ手法が委ねられていると、デプロイの質に差が生じてまばらになってしまって、サービス全体として見たときにその質が低下しているときもあります。そのようなときには、Spinnaker Manage Pipelineを使うことをおすすめします。どういった機能かを紹介いたします。

Spinnaker Manage Pipeline

Managed Pipelineとは、Managed Pipelineの雛形になるManaged Pipeline Template、MPTと呼ばれるテンプレートに設定情報を渡してできるパイプラインのことです。下の図のようにPipeline Configurations、パイプラインの設定を渡して、テンプレートを基にManaged Pipelineを作成します。パイプラインの設定は、JSONファイルでもGUIでもできます。

このManaged Pipelineは、普通のGUIで作成したパイプラインとは少し機能が違っています。主な違う機能を3つ紹介します。1つはSync機能です。MPTが更新されると、そのMPTが生成されたすべてのパイプラインも同時に変更される点です。

この想定されるユースケースとしては、例えばプラットフォームチームなど、ある程度全体を見ているチームがパイプラインテンプレートを提供して、各マイクロサービスのデプロイ手法を整えているとき、そのプラットフォームチームがテンプレートを更新することによって、全マイクロサービスのデプロイ手法を使えます。

2つ目の機能としては、Immutable機能です。Managed Pipelineは作成したあと、直接変更ができません。API経由のみ変更できます。Configuration機能では、必要な部分だけMPTの一部を変数化して、あとから変更できるようにできます。

なので、2つ目のImmutable機能とConfiguration機能のバランスを取ることによって、一部だけデベロッパーにいじってもらって項目を公開、ということもできます。Managed Pipeline機能を使えば、テンプレート管理をするだけで、横断的に全マイクロサービスのパイプラインの管理ができるので、サービス全体の質を高められます。

Managed Pipelineの実用例

もう少し詳しく図で説明します。ServiceA、B、Cのチームがあり、それぞれパイプラインの設定があって、MPTを使って各パイプラインを作成しています。

例えば、プラットフォームチームがデプロイ先を変更するMPTをバージョン2に上げた時に、それに紐づいてできたパイプラインすべてを自動的に更新できて、すべてのパイプラインのデプロイ先を自動で、デベロッパーが何もする必要がなく更新できます。また、デプロイ先を変更するだけではなく、あとのチームのベストプラクティスを追加します。

例えばカナリアデプロイでも、他のより良いプロダクトと合わせて、より質の良いカナリアデプロイできるとなったときに、そのテンプレートをそれに応じて実装することによって、すべての紐づくパイプライン、マイクロサービスで実装できます。

そのため、全マイクロサービスのデベロッパーにベストプラクティスの実装をお願いするだけではなくて、テンプレートを更新するだけで実装できるので、組織全体のベストプラクティス適用が簡単になります。

2つ目のImmutable機能は、パイプライン設定を渡せる以外は、すべてを更新できないかたちになっています。

この図であるように、エディットできないので、一度良いパイプラインを生成したとしても、後々上書きされてパイプラインを壊されたり、意図せず壊してしまったり。いろんなリスクがあると思うんですけど、それを防げるので、プラットフォームチームや組織は安心してパイプラインを信用できます。

3つ目のConfiguration機能では、設定値のみをデベロッパーが設定できます。例えばDockerコンテナのポートを設定する必要があるテンプレートがあったとき、デベロッパーがそのパイプラインを作るときに設定できるようになる項目です。このようにしてGUIでその設定項目を1つだけ設定することによって、パイプラインを簡単に作成できるようになります。

この3つの主な機能を使うことによって、マイクロサービスに必要な最低限の設定だけを公開して、あとから変更されることなく、全マイクロサービスのデプロイを標準化管理ができる。なのでManaged Pipelineを使うことは非常に有用です。

Snowflakeパイプライン

1つ目がManaged Pipelineをパイプラインに対して使っていくプラクティスでした。2つ目はSnowflakeパイプラインという問題に対して取り組んでいきたいなと思います。

Snowflakeは、インフラエンジニアだったらよく知っているかもしれないですが、「一時的に変更を手で加えることによって、後々どうやってそれを再現したらいいのかわからない」といったものを、Snowflakeと呼んでいます。

Snowflakeパイプラインというのは、例えば、デベロッパーが手探りでパイプラインを更新していって、でもそれを消してしまい、復元したいとなっても作り方がわからない。となると、いろんな問題が発生してしまいます。しかもパイプライン自体はGUIでぽちぽち作成するので、非常に管理が難しいです。

後々まったく同じようなパイプラインを作ろうと思っても、どのように設定していくか直感的ではない。これも同様のSnowflakeパイプラインを作るもとになってしまいます。つまり、このようなGUIでパイプラインを作ったり管理したりすることは、非常にリスクがあることです。人為的ミス、設定ミス、または消してしまったり、復元できないことを含めて、いろんなリスクがあります。

Managed PipelineはSpinnakerのAPI経由で作成できるので、ある意味プログラムから設定できます。Pipeline ConfigurationsもJSONで書けて、SpinnakerのAPIにJSONを投げることで、Managed Pipelineを生成できます。その場合に、MPTをJSONの中で指定することになります。

GUIで管理せず、パイプラインをコード管理するプラクティスのことを、Pipeline as Codeと呼べると思います。最近ではInfrastructure as Code、Policy as Codeと、いろんなas Codeという言葉が出てきますが、パイプラインも同様にPipeline as Codeと呼べると思います。他の〇〇 as Codeと同様に、いろんなメリットがあります。

1つはコストの削減です。コードを管理できるようになれば、GUI上で人間がぽちぽちパイプラインを作成することなく自動化などもでき、作業工数を減らせるようになります。2つ目はスピードの向上です。自動化や効率化を非常にしやすくなって、開発速度がより高速になります。デベロッパーがGUIでぽちぽちする時間も減るはずです。

3つ目はリスクの低減です。先ほどのSnowflakeパイプラインで紹介しましたが、後々から復元できないようなパイプラインができてしまったり、ある程度知識を要するようなパイプラインを作成することがなく、同じコードを書けば誰がやっても同じ結果になるようなJSONを書くことになります。それによって属人性もなくなって、組織全体としてリスクを低減できるのではないかなと思います。

またコードはGUI上で管理され、それ以上に管理しやすいです。そのため、管理コストの面でも非常にメリットがあります。

Spinnakerのデプロイ手法でより安全にリリースフローが設計できる

最後にまとめて終わりたいと思います。マイクロサービスの継続的デリバリーの中で、Spinnakerが実装しているさまざまなデプロイ手法を選定することによって、より安全なアプリケーション、リリースフローを設計できるようになります。どのデプロイ手法を使うかは組織によって判断が必要ですが、Spinnakerではカナリアデプロイなど、一般的により安全なデプロイ手法が用意されています。

また、SpinnakerのManaged Pipeline機能を使うことによって、マイクロサービスのデプロイの質を担保できるようになります。Managed Pipelineをする中でも、Pipeline as Codeのプラクティスを導入することによって、そのメリットを享受できます。

パイプラインをコード管理することによって、より管理しやすく、リスクを低減できることにより、いろんな自動化を推し進められるのではないかなと思っています。これらのことを合わせて、Spinnakerという継続的デリバリープラットフォームの多くの機能や、それに紐づくプラクティスを実践することによって、よりアプリケーションリリースフローが安全で、開発効率などを上られるようになると思います。

今日は「Spinnakerで実践するマイクロサービスの安全なリリースフローとベストプラクティス」というタイトルで発表いたしました。クラウド運用について継続的デリバリーは非常に重要な要素です。Spinnakerの機能をうまく使うことによって、安全なリリースを実現できるようになれればうれしいです。

本日はご視聴いただき、誠にありがとうございました。