nazolabo

Webエンジニアのnazoさんのブログです。お仕事募集中です。 https://nazo.dev/

クラウドインフラにおけるResourceとDeployment

何の話

クラウドインフラ(AWSGCPなど、その中で取り扱うもの)で、ResourceとDeploymentという境界を分けるとうまく整理できるのではないかという話です。

※この話は私が勝手に言っている内容です。用語定義や概念など一般的なものでないので、あくまで参考として読んでいただければと思います。

前提

現代のアプリケーションは12Factor Appに基づき、Buildフェーズで作られたビルドに環境変数で設定を当てることによってデプロイが完了します。RAILS_ENVのような設定は使いません。

またCIでビルドされたイメージには一意のタグが付き(いわゆるlatest運用ではない)、それに環境変数を当てることで一意のリリースが作成されます。12Factor Appの「V. ビルド、リリース、実行」も参考にしてください。

Resource

一般的なクラウドリソースをResourceと呼びます(ダジャレを言いたいわけではないです)。

Resourceは一度作ると「そのResourceが持っている機能で」操作を行うことがありますが、Resourceそのものを作成した時と同じ方法で操作することはほぼありません。

Terraformは現代においてベストなIaCツールの1つですが、その理由に「そうなるべきである状態を定義し、インフラ側をその状態になるようにする」という構造で作られているからです。

「あるべき状態を定義してそれを実行する」という店ではAnsibleもそうでしたが、Ansibleは書き方が手続き型で、かつ何でも書けてしまうという難点がありました。しかしTerraformは書き方を大幅に制限することで、「インフラのあるべき状態」以外のことはほぼ書けないようになっています。

Deployment

ビルドしたリソースを配置する作業に付随するものはDeploymentです。

Resourceは一度作ると「その作業プロトコルで」それ以上の操作をすることは基本的にありませんが、Deploymentは「同一の作業プロトコルで」初期配置やビルドの更新などを行います。

例えばk8sのコントロールプレーン(AWSならEKS)はResourceですが、その上で行うk8sの操作は全てDeploymentと分類できます。(k8s自体のDeploymentとは別の話です。DaemonSetだろうとLoadBalancerだろうとここでは全てDeploymentです)

ちょっと話が逸れますが、AWS RDSそのものはResourceで、その中に入るDBのデータはDeployment、というようなイメージを、インフラ全体とアプリケーションに対して定義しているような感じだと思っています。

なぜ分けるのか

例えばAWS ECSのタスク定義には通常最新のイメージのタグを記述しますが(これはk8sでも同様ですが)、最新のイメージのタグは通常CIで決定されますので、アプリケーションのビルドCIと同居している必要があります。タスク定義のライフサイクルがCIと違う場所に存在する、例えばクラウドリソースと同じライフサイクルで存在すると、CIに入れてしまうとアプリケーションの更新とクラウドリソースの更新が混ざる可能性がありますし、CIに入れないと最新のタグを取得できないので最新のイメージで適切に更新する方法がありません。(latestタグ運用はダメ絶対)

つまり、Resourceというのは「変化しないもの」であり(厳密には自動メンテナンスで勝手にバージョンを上げられて…みたいなこともありますが)、Deploymentは「変化するもの」ということです。

私はECSのサービスやタスク定義をTerraformで他のResourceと同一ライフサイクルで管理したことがありましたが、上記問題により辛い結果になっていました(その時はlatest的なタグをCIから同時にpushすることで、Terraformから更新する時だけは仕方なくそちらを参照するという苦肉の策で回避していました)。TerraformでECSタスク定義やk8sを管理すること自体は否定しませんが(それが良いかどうかは別として)、Resourceと同一のライフサイクルにするのは無理があるのではないかと考えています。

k8sYAMLは一見「あるべき状態を書く」ようになっていますが、それは通信プロトコル的な部分の話で、現実にはCIで毎回違うイメージのタグに書き換えてデプロイすることになります。このYAMLの部分は下記参考記事のInfrastructure as Dataであり(この呼び方は議論の余地があると思いますが、概念の分類としては良いと思います)、それを実運用するには通常その上にCodeが必要になります。

deeeet.com

個人的には、Deploymentというのはインフラというより「アプリケーションという名のデータ」というほうが近く、そもそもこれはInfrastructureなのか?と思うところがありますが、これがk8sになるとALB Ingress Controllerやらexternal-dnsやらでクラウドリソースそのものも制御できてしまうので、このあたりがk8sをより複雑にさせているのではないかと思うところです。

まとめ

用語は正直何でもいいし英語圏の人たちにちゃんと決めてほしいのですが、ともかく「デプロイするコンテナ」というのは通常のクラウドリソースとは別物なのではないか、ということが言いたかったことです。

Deploymentは「あるべき状態」が日々変化するため、そういう目的で管理するのが難しいですが、しかし統一的な「あるべき状態」を維持できるツールにしておかないと管理できていないサーバー(「構成ドリフト」とか「スノーフレークサーバー」とかそういうやつ)が生まれます。Resourceとはライフサイクルを分けつつ、コードと実態が乖離しない、そもそも乖離できないようにする構成を考えましょう。