ようこそ!このページにたどり着いたということは、すでに 第1回(なぜ必要か)をお読みいただき、クラウドネイティブな開発者環境を適切に構築する方法をさらに知りたいとお考えなのでしょう。素晴らしいですね!
ここからは、ある既存のプロジェクトチームを例に、開発ワークフローをどう改善できるかを見ていきます。
本ガイドは GCP(Google Cloud Platform)を前提に書いていますが、同じ考え方は AWS にも応用できます。
Photo by Jason Richard on Unsplash
📖 ケーススタディ
MajesticFantastic という会社が、決済関連のプロダクトをいくつか展開しています 💸
請求プロジェクトチームは、請求アプリケーションの開発を担当しています。
構成は次のとおりです。
- GKE 上にコンテナとしてデプロイされた数個のマイクロサービス 🛳
- 利用中の GCP クラウドサービス:Pub/Sub、Cloud SQL(PostgreSQL)、Cloud Monitoring、Container Registry
- 現在の環境:Dev、Prod
- 開発者2名(David と Martha)のチーム。会社が急成長フェーズにあるため、まもなく Ezekiel を含む数名の開発者が新たに加わる予定です。楽しみですね!🚀
概念実証(POC)
新しい環境タイプとして「Personal 環境」を導入します。
Personal 環境向けの POC は、次の要素で構成します。
- Host プロジェクトとして機能する GCP プロジェクト。GKE クラスタ、Cloud SQL インスタンス、GCR 上のコンテナイメージをここでホストします。
- 複数の GCP Personal プロジェクト(開発者ごとに1つずつ)。各プロジェクトには、開発者単位にスコープされた非共有リソースを置きます。本ユースケースでは、Pub/Sub のトピックとサブスクリプションをここで持ちます。
- Shared VPC。ホストは Host プロジェクトで、各 Personal プロジェクトは Shared VPC のサービスプロジェクトとして機能します。
GKE クラスタのマルチテナント化
環境ごとに K8s ネームスペースを割り当てます(例:David の環境には david-env、Martha には martha-env、といった具合です)。
各環境は自分のネームスペースのみを使い、他の環境のネームスペースにあるリソースには依存しないようにします。
注:今回はセキュリティ面の制御は行いません。セキュリティ対策については、本記事の最後で改めて触れます。
Cloud SQL のマルチテナント化
Cloud SQL は ユーザーとデータベースに対応しているので、環境ごとにユーザーとデータベースを割り当てられます(使うのは Cloud SQL インスタンス1台のみで、課金も1台分だけです!)。
プライベートな Cloud SQL インスタンスを1つ作成し、プライベートサービスアクセスを使って Shared VPC に「接続」します。
いよいよ実践編!👩🔧
developer-envs リポジトリには、関連する IaC と GitOps のコードがすべて含まれています。
Infrastructure-as-Code(IaC)
手作業でやる必要はありません。Terraform を Infrastructure-as-Code として使い、ブートストラップを自動化します。コードはこちら!
環境ごとの K8s ネームスペースのセットアップ、およびインフラ関連パラメータ(Pub/Sub トピック名や GCP プロジェクト ID など)を保持する共通 ConfigMap の作成には、Terraform Kubernetes Provider を使います。
ソリューション全体を通じて、Cloud Foundation Toolkit の一部である Google の Terraform モジュールを使ってみましたが、とても扱いやすかったです。Google のベストプラクティスも織り込まれているので、ぜひ一度目を通してみてください。
本コンセプトにおいて、Terraform のような Infra-as-Code ツールの活用は欠かせません。人為ミスを伴う煩雑な作業を減らして自動化し、スケールしても全構成の整合性を保つことが目的だからです。今少し手間をかければ、後の作業はずっと楽になります。
GitOps
続いて、K8s 上で複数の環境を制御・デプロイするために ArgoCD も使います。ArgoCD は人気の GitOps 継続的デリバリーツールで、個人的にはマルチテナントのユースケースとの相性が抜群だと感じています。コードはこちら!
K8s リソースの大半は YAML で定義し、構成のカスタマイズには Kustomize を使います。
Kustomize は構成管理ツールで、「ベース」となる構成と、その上に重ねる多数の「オーバーレイ」を定義でき、すべてが共通のベース構成を共有します(簡易的な継承のようなものです)。複数環境に共通の構成基盤を持たせたいケースには最適です。
ありがたいことに、CD ソリューションの ArgoCD は Kustomize との統合をサポートしています。
Kustomize はシンプルで使いやすいと思いますが、もちろん Helm のような別ツールでも問題ありません。
サンプルマイクロサービス
Go で書かれた、ごくシンプルで素朴なマイクロサービスを2つデプロイします。
env-producer マイクロサービスは、10秒おきに Pub/Sub トピックへ決済イベントを定期的にパブリッシュします。
env-consumer マイクロサービスは、Pub/Sub から「決済イベント」のメッセージを受け取り、PostgreSQL のテーブルに永続化します。
ここで重要なのは、マルチ環境構成がサービス側からは見えないようになっている点です。環境の詳細は環境変数として渡しています。設定をコードから切り離すのは Twelve-Factor の重要な実践のひとつで、押さえておきたい考え方です。
つまり、これらのマイクロサービスは各環境で個別に動作し、その環境固有のリソースとだけ連携するということです。

セットアップと起動 🏃🏻♂️
動かしてみるには、サンプルリポジトリをクローンし、README.md の手順に従ってください。

その後、ArgoCD のコンソールは次のような表示になるはずです。
これは、1つのダッシュボードですべての環境を一望できる場として機能します。当然、ここに dev や prod など他の環境も、別の ArgoCD「プロジェクト」として追加したくなるはずです。
argocd-config というアプリケーションがある点に注目してください。これは ArgoCD 自身の設定ファイルとインストールファイルを自己同期する役割を担います。さらに、開発者ごとに1つずつ、合計2つのアプリケーションが追加されています。
自分の環境に変更をデプロイする方法
あるサービスに変更を加え、それを自分の環境にデプロイしたいとします。どのような選択肢があるでしょうか?
選択肢1:カスタムイメージをビルドする
ソースコードを変更し、新しいコンテナイメージをビルドします。あとは ArgoCD のアプリケーションでイメージタグをさっと書き換えるだけで、新しいイメージがすぐデプロイされます。

ArgoCD のアプリケーション情報画面。開発者はイメージタグを書き換えて Save をクリックできます
これは手作業でも、CI パイプラインやカスタムスクリプトによる自動化でも実現できます(ArgoCD には CLI もあり、自動化に使えます)。
選択肢2:ローカルで動かす
えっ……?それって、今やろうとしていることと矛盾していませんか?
そこで登場するのが Telepresence です。Telepresence は、最近触れた中でも特に気の利いたツールのひとつで、私自身も何度も使っており、開発者としての生産性を大きく押し上げてくれました。
機能を一文で説明するのはなかなか難しいのですが、やってみましょう。公式サイトから引用した説明はこちらです。
Telepresence は、Kubernetes クラスタで稼働している通常の Pod を、双方向のネットワークプロキシに置き換えます。この Pod は Kubernetes 環境のデータ(TCP 接続、環境変数、ボリュームなど)をローカルプロセスへプロキシします。ローカルプロセスのネットワークは透過的に上書きされ、DNS 呼び出しや TCP 接続がプロキシ経由でリモートの Kubernetes クラスタへルーティングされます。
もっとかみ砕くと、サービスをローカルマシン上で動かしながら、入出力の接続、環境変数、ボリュームを K8s クラスタへプロキシしてくれる、ということです。便利ですよね!👍
たとえば env-consumer マイクロサービスに変更を加えて試したい、としましょう。次のコマンドを実行します。
すると数秒のうちに、変更が反映された状態でデプロイされ、稼働を始めます。
仕組みとしては、サービスの Pod をプロキシ Pod に置き換え、サービスはローカルで実行しながら、そのプロキシ Pod とやり取りする形になります。
面白いのは、ローカルで動いているアプリなのに、実際にはリモートの Pub/Sub と Cloud SQL(PostgreSQL)の両方につながっているという点です!
しかも、アプリケーションコードを書き換えたり、証明書やシークレットキーを設定し直したりする必要はありません。Personal 環境でも本番と同じコードがそのまま動くのです!
作業を終えて Ctrl+C を押せば、イメージは元の状態に戻ります。気持ちいいですね!🤩

Telepresence を使ってサンプルサービスを動かすデモ
想像してみてください。バグを修正し、Telepresence を起動し、数秒待って動かしてみたら、自分のせいでサービスがクラッシュしていた——あちゃー、もう一度直す。フィードバックループがかなり高速だと感じられるはずです!😁
ここでは Docker イメージを一切ビルドしていない点にもご注目ください。修正したソースコードをビルドし、実行ファイルをローカルで動かしているだけです。Docker イメージをビルドして差し替える方式にすることもできます。
Personal 環境とオンボーディング
Ezekiel が新しい開発者としてチームに加わりました!ようこそ!ノートPCとちょっとしたグッズも受け取ったようです。やった!🥳
オンボーディングの一環として、Ezekiel がアプリケーションやインフラに触れて小さな変更を加え、その影響を確かめられるよう、Personal 環境を用意してほしいと頼まれました。
手順は次のとおりです。
tf/personal.tfvarsファイルを編集し、テナント一覧に Ezekiel を追加します。
2. terraform apply -f personal.tfvars を実行して変更を適用します。
3. 以下のスニペットを argo/apps/applications.yaml に追記し、Ezekiel の環境用の ArgoCD アプリケーションを追加して、コミット&プッシュします。
これで完了です!ArgoCD は apps フォルダを追跡するように同期されているので、ezekiel-env が追加されたことを自動で検知し、環境を整えてくれます。Ezekiel もきっと喜んでくれるはずです。
Personal 環境とオフボーディング
あらら!David が新しいチャンスを求めてチームを去ることになりました!
残念です、寂しくなりますね。⭐️ 😩
とはいえ、おかげで Personal 環境がいかに簡単に片付くかをお見せできます。😌
argo/apps/applications.yaml を開いて david-env のアプリケーション定義を削除し、コミット&プッシュするだけです。ArgoCD は apps フォルダを追跡するように同期されているので、david-env が削除されたことを自動で検知し、環境を削除してくれます。
その後、tf/personal.tfvars のテナント一覧から david を削除し、続けて terraform apply -f personal.tfvars を実行して、環境のインフラも削除しましょう。
これで完了!David の痕跡はどこにも残りません 💀
👣 次のステップ
これを自社向けに採り入れたい場合は、ぜひ自由にどうぞ。ただし、次のような追加の検討事項があります。
あくまで POC
すでに述べたとおり、これは POC であり、サンプルや「とりあえず動かしてみる」用途を想定したものです。実装の一部は簡潔さを優先して簡略化しています。これをそのままベストプラクティスとは捉えず、ご自身の要件や好みに合わせて調整してください。
セキュリティ
前回触れたとおり、本ソリューションではセキュリティが論点になり得ます。これをベースに、セキュリティと分離性を高める方法はいくつかあります(RBAC、ネットワークポリシー、リソースクォータ、Pod アンチアフィニティなど。詳しくはこちらをご覧ください)。
マルチテナンシー
ここでは GKE、Pub/Sub、Cloud SQL のようなクラウドサービスのマルチテナンシー例を取り上げましたが、同じ考え方は他のクラウドサービスにも応用できます。
開発者ごとの GCP プロジェクト
現状、開発者ごとの GCP プロジェクトのスコープはかなり限定的です。これは、今後スコープを広げて磨き込むためのベースラインです。たとえば、ネームスペース固有のログやメトリクスを、特定の開発者の GCP プロジェクトへ送るルーティングを設定できます。あるいは、本流に含まれないカスタムリソースをその GCP プロジェクトで立ち上げ、想定どおり動くかを試す、といった使い方もできます。開発者ごとの GCP プロジェクトは必須ではなく、あくまで一案ですので、不要なら省いて構いません。
Shared VPC
本構成では Shared VPC を利用しており、これによって複数の GCP Personal プロジェクトが同じ VPC ネットワークを共有できます。考慮すべき IAM の前提条件がいくつかあります。たとえば、Shared VPC 内でリソースを作成するには、開発者の IAM ユーザーが Host プロジェクトで compute.networkUser ロールを持っている必要があります。
代替ソリューション
以下の代替ツールも、同様の課題解決を狙ったものです。中には有償のものもあります。私の知る限り、これらの代替手段は本 POC のように、インフラとデプロイ構成をひとそろいに仕立てる「フルスタック」なソリューションは提供していないようで、主眼はあくまで Kubernetes 部分にあります。それぞれに状況に応じた長所と短所があるので、その点を踏まえて検討してください。
以上です!楽しんでいただけたなら幸いです 🙂
DoiT International のアーキテクトとエンジニアは、インフラとソフトウェア開発の橋渡しに常に取り組んでいます。両者は生産性と信頼性という共通のゴールを目指す仲間だと考えているからです。
お読みいただきありがとうございました! 引き続きつながりたい方は、DoiT Engineering Blog、DoiT LinkedIn チャンネル、DoiT Twitter チャンネルをフォローしてください。キャリアのご相談は https://careers.doit-intl.com をご覧ください。