0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

既存 OCI を Crossplane へ:Observe-only、Platform API、GitOps 連携を整理する

0
Posted at

初めに

前回の記事では、OCI Provider を使って Object Storage Bucket を作る一周を整理しました。

流れは、Crossplane core、OCI Provider、Secret、ProviderConfig、Bucket Managed Resource、READY / SYNCED、OCI Console、delete でした。

今回は、その先の話です。

すでに OCI 上に resource が存在する場合、いきなり Crossplane に完全管理させるのは危険です。

既存の運用、IAM、削除責任、命名規則、手作業での変更履歴があるためです。

そこでまず見るべきなのが、Observe-only です。

Observe-only は、既存 OCI resource を壊さずに Kubernetes 側へ観察値を載せるための入口です。

そこから、どこまで Crossplane に任せるか、どこから Platform API として利用者に見せるか、GitOps とどうつなげるかを考えます。

この記事では、次の流れで整理します。

既存 OCI resource
  -> Observe-only
    -> managementPolicies
      -> external-name
        -> Platform API
          -> GitOps

この記事のゴール

この記事のゴールは、次の三つを説明できるようになることです。

Observe-only
  既存 OCI resource を壊さず、Kubernetes 側から状態を見る入口

Platform API
  Bucket そのものではなく、チームが必要とする保存能力として見せる API

GitOps 連携
  Git / Argo CD が desired state を同期し、Crossplane が OCI 側と reconcile する流れ

特に大事なのは、Observe-only を「完全管理の前段階」として見ることです。

最初から Create / Update / Delete まで許可するのではなく、まず Observe だけで既存 resource と Kubernetes resource の対応を確認します。


既存 OCI resource をいきなり完全管理しない

新規に Bucket を作る demo では、Crossplane が resource を作り、状態を見て、必要なら削除します。

しかし、既存 OCI resource では前提が違います。

たとえば、すでに運用中の Object Storage Bucket があるとします。

その Bucket には、既存の IAM policy、利用中の application、手動で設定した rule、運用チームの削除手順があるかもしれません。

ここでいきなり Crossplane の Managed Resource を作り、Create / Update / Delete まで許可すると、既存運用と衝突する可能性があります。

最初に見るべき問いは、次のようなものです。

この resource は誰が変更しているか
削除してよい owner は誰か
Crossplane は読むだけでよいのか
将来的に Update まで任せるのか
Delete まで任せるのか

この判断をしないまま管理へ移すと、削除責任と変更責任が曖昧になります。

Observe-only は、この曖昧さを避けるための安全な入口です。


managementPolicies は操作範囲を決める

Crossplane v2 の Managed Resource には、spec.managementPolicies があります。

これは、controller が外部 resource に対してどの操作を行ってよいかを決める field です。

Crossplane の core API では、主な操作として次の値が定義されています。

Observe
Create
Update
Delete
LateInitialize
*

意味を簡単に整理すると、次のようになります。

management action 意味
Observe 外部 resource の状態を読み、status.atProvider などを更新する
Create 外部 resource を作成する
Update spec.forProvider に基づいて外部 resource を更新する
Delete Managed Resource の削除時に外部 resource も削除する
LateInitialize 外部 resource から観察した値で未指定の spec.forProvider を補完する
* 上記の操作をすべて許可する

Observe-only の基本は、次のように Observe だけを許可することです。

spec:
  managementPolicies:
    - Observe

この状態では、Crossplane は外部 resource を読むだけです。

外部 resource を作成、更新、削除しません。

つまり、既存 OCI resource を壊さずに、Kubernetes 側から状態を見られるようになります。


deletionPolicy より managementPolicies を優先して考える

既存 resource を扱うとき、deletionPolicy だけを見て判断すると危険です。

OCI Provider の quickstart では、managementPolicies は常に deletionPolicy を上書きする、と説明されています。

たとえば、managementPoliciesDelete が含まれていない場合、deletionPolicy: Delete があっても外部 resource は削除されません。

逆に、managementPoliciesDelete が含まれている場合は、削除操作まで controller に許可していることになります。

判断するときは、次の順番で見ると分かりやすいです。

1. managementPolicies に Delete が含まれているか
2. deletionPolicy は Delete か Orphan か
3. その resource の削除 owner は誰か
4. OCI 側で削除後確認を誰が行うか

Observe-only では、まず Observe だけにします。

変更や削除を許可するかどうかは、所有権と運用責任を合意してから決めるのが安全です。


external-name は既存 resource を指す鍵

Observe-only では、Kubernetes resource と既存 OCI resource を対応づける必要があります。

そこで重要になるのが、crossplane.io/external-name annotation です。

Kubernetes 側の metadata.name は、Kubernetes resource の名前です。

一方、crossplane.io/external-name は、外部 resource の識別子として扱われます。

公式 quickstart の Observe-only 例では、既存 KMS Vault を指すために、次のような形で external-name を使っています。

apiVersion: kms.oci.m.upbound.io/v1alpha1
kind: Vault
metadata:
  name: vault1
  namespace: team-a
  annotations:
    crossplane.io/external-name: <EXTERNAL_RESOURCE_OCID>
spec:
  managementPolicies:
    - Observe
  forProvider:
    compartmentId: <COMPARTMENT_OCID>
    displayName: vault1
  providerConfigRef:
    kind: ProviderConfig
    name: default

この例では、managementPolicies: ["Observe"] によって、Crossplane は既存 Vault を読むだけになります。

Bucket のような resource でも考え方は同じです。

ただし、外部名の形式は resource と Provider の実装によって異なる場合があります。

Object Storage Bucket では、kubectl getEXTERNAL-NAMEn/<namespace>/b/<bucket> のような形式が表示されることがあります。

実際に既存 Bucket を取り込む場合は、対象 provider version の CRD、examples、kubectl get の出力、quickstart を確認してください。

ここでのポイントは、metadata.name と OCI 側の実体名を混同しないことです。

OCI 側では、Bucket 名だけでなく、Object Storage namespace、compartment、region も合わせて確認します。


Observe-only から完全管理へ進む前に責任境界を決める

Observe-only は、最終形ではなく入口です。

そこから Crossplane にどこまで任せるかを決めます。

大きく分けると、次の選択肢があります。

方針 向いている状況
Observe から開始 既存運用が強く、まず状態共有だけしたい
段階移行 変更責任を整理しながら、少しずつ Crossplane に寄せたい
新規のみ管理 既存 resource には触らず、新規作成分だけ標準化したい
完全管理 作成、更新、削除まで Crossplane に任せたい

重要なのは、どれが正解かではありません。

既存運用の依存度と、Crossplane に許可する操作範囲を合わせることです。

特に、完全管理へ移す場合は、次の点を明確にしておきます。

誰が変更するか
誰が削除するか
どの IAM policy で実行するか
Delete を許可するか
finalizer が残った場合に誰が対応するか
削除後に OCI 側で何を確認するか

この合意なしに CreateUpdateDelete を許可すると、運用側の期待と platform 側の reconcile が衝突しやすくなります。


Platform API は Bucket ではなく保存能力を見せる

ここまでの話は、既存 OCI resource をどう安全に Kubernetes 側へ載せるかでした。

次に考えるのは、利用者に何を見せるかです。

利用者が本当に欲しいのは、OCI Object Storage の全 field ではないことが多いです。

たとえば、利用者は次のような要求を持っているかもしれません。

チーム用の保存場所がほしい
環境ごとに分けたい
命名規則は platform 側でそろえてほしい
必要な接続情報だけ受け取りたい
削除や変更の責任範囲を明確にしたい

この場合、利用者向け API は Bucket そのものではなく、TeamStorage のような形にできます。

apiVersion: platform.example.org/v1alpha1
kind: TeamStorage
metadata:
  name: team-a-logs
spec:
  team: team-a
  environment: dev
  retentionDays: 30
  accessLevel: private

ここでは、OCI の compartmentId、Object Storage namespace、IAM policy、tag、Bucket naming rule を利用者に直接見せていません。

それらは Platform API の裏側で標準化します。

TeamStorage
  利用者が判断する項目

Composition
  標準命名、配置先、policy、outputs を決める

Managed Resource
  OCI Bucket、IAM policy、Secret などを作る

これが Platform API 化の考え方です。

OCI の細かい resource をそのまま利用者に渡すのではなく、利用者が判断すべき項目だけを残します。


Platform API 化するときの判断軸

Platform API を作るときは、何を隠し、何を見せるかが重要です。

判断軸は、次のように整理できます。

項目 利用者に見せるか
team / environment 見せることが多い
storage class / retention 利用者判断にしたい場合は見せる
compartmentId 多くの場合は platform 側で決める
Object Storage namespace 多くの場合は platform 側で決める
IAM policy platform 側で標準化することが多い
Bucket name 命名規則に沿って生成することが多い
connection details 必要な出力だけ渡す

すべてを隠せばよいわけではありません。

利用者が判断すべきものまで隠すと、逆に使いにくい API になります。

一方で、OCI の実装詳細をそのまま見せると、Platform API ではなく Provider API の薄い wrapper になります。

Platform API のポイントは、利用者の判断と platform 側の標準化を分けることです。


GitOps 連携では Argo CD と Crossplane の役割を分ける

Crossplane の resource は Kubernetes resource です。

そのため、GitOps tool と組み合わせやすいです。

OCI Provider repo には、Argo CD を使って Crossplane OCI Provider の platform や claim を deploy する examples も含まれています。

ただし、GitOps と Crossplane の役割は分けて見る必要があります。

Git / Pull Request
  YAML の変更を review する

Argo CD
  Git の desired state を Kubernetes cluster に sync する

Kubernetes API Server
  resource を保存する

Crossplane
  Kubernetes resource を observe し、OCI 側と reconcile する

OCI
  実際の cloud resource を保持する

Argo CD が OCI API を直接呼ぶわけではありません。

Argo CD は Kubernetes resource を同期します。

OCI API と状態合わせするのは Crossplane Provider です。

この分担を押さえると、GitOps 化したときの debug がしやすくなります。


GitOps で見る状態は二段階ある

GitOps 連携では、状態確認が二段階になります。

一つ目は、Argo CD の同期状態です。

Git の内容が cluster に apply されているかを見ます。

二つ目は、Crossplane の reconcile 状態です。

Kubernetes resource が OCI 側と同期できているかを見ます。

Argo CD
  Synced / OutOfSync / Healthy

Crossplane
  READY / SYNCED / conditions / events

OCI
  実際の resource 状態

Argo CD が Synced でも、Crossplane の READYSYNCEDFalse になることはあります。

これは矛盾ではありません。

Git の YAML は cluster に反映されているが、OCI 側との状態合わせに失敗している、という意味です。

たとえば、ProviderConfig の参照ミス、Secret の key の間違い、OCI IAM policy の不足、compartmentId の誤りなどが原因になります。

GitOps では、Argo CD の状態だけで完了と見ないことが大事です。

Crossplane の conditions と OCI Console まで見ることで、実際の cloud resource とつながります。


GitOps に載せるもの、載せないもの

GitOps 化するときは、何を Git に置くかも重要です。

基本的には、宣言的に管理したい resource を Git に置きます。

XRD
Composition
Function
Provider
ProviderConfig
XR / Claim
Managed Resource

一方で、秘密情報の扱いには注意が必要です。

OCI API key、private key、fingerprint などを平文で Git に置くのは避けます。

実運用では、Sealed Secrets、External Secrets、Vault、OCI Vault など、組織の secret 管理方式に合わせます。

この section の範囲では、少なくとも次の分担を覚えておくと十分です。

Git
  desired state と review の場所

Secret 管理
  credentials を安全に渡す場所

Argo CD
  Git から Kubernetes へ同期する役割

Crossplane
  Kubernetes から OCI へ reconcile する役割

よくある混乱

一つ目は、Observe-only を import 完了と見てしまうことです。

Observe-only は、既存 resource を壊さず観察する入口です。

変更や削除まで任せるには、managementPolicies、IAM、削除責任を別途確認します。

二つ目は、metadata.nameexternal-name を混同することです。

metadata.name は Kubernetes 側の名前です。

external-name は外部 resource の識別子です。

既存 OCI resource を扱う場合は、OCI 側の namespace、compartment、region も合わせて確認します。

三つ目は、GitOps の Synced を cloud resource の成功と見てしまうことです。

Argo CD の Synced は、Git の YAML が Kubernetes に同期された状態です。

OCI API との状態合わせが成功したかどうかは、Crossplane の READYSYNCED、conditions、OCI Console で確認します。


まとめ

今回は、既存 OCI resource を Crossplane に近づけるときの入口として、Observe-only、Platform API、GitOps 連携を整理しました。

ポイントは、次の三つです。

Observe-only は既存 OCI resource を壊さず観察する入口
managementPolicies は Crossplane に許可する操作範囲を決める
GitOps では Argo CD が同期し、Crossplane が OCI と reconcile する

既存 resource を扱うときは、最初から完全管理を目指す必要はありません。

まず観察し、外部名と OCI 側の実体を対応づけ、責任境界を決めてから管理範囲を広げる方が安全です。

Platform API 化では、Bucket という実装部品をそのまま見せるのではなく、チームが必要とする保存能力として切り出すことがポイントです。

次は、Terraform との分担、責任境界、lifecycle の考え方を整理します。


参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?