初めに
前回の記事では、Composition の実装として Patch & Transform、Composition Functions、Pipeline mode を整理しました。
そこでは、Composition は OCI API を直接呼ぶ処理ではなく、Managed Resource の desired state を作る場所だと説明しました。
今回は、その先に進みます。
実際に OCI Object Storage Bucket を作る流れを使って、OCI Provider の構成、認証、Managed Resource の状態確認を一つにつなげます。
この内容は、以前書いた Crossplane Provider for Oracle Cloud Infrastructure (OCI) 入門 の実操記録を学習の流れとして参考にしています。
ただし、実際に使う apiVersion、Provider の package tag、ProviderConfig の種類、example manifest は、必ず最新の公式 repo と quickstart を確認してください。
OCI Provider は provider release によって API group や field が変わる可能性があります。
この記事では、細かい option を全部説明するのではなく、初学者がまず覚えるべき一周に絞ります。
Crossplane core
-> OCI Provider
-> Secret
-> ProviderConfig
-> Bucket Managed Resource
-> READY / SYNCED
-> OCI Console
-> delete
この記事のゴール
この記事のゴールは、OCI Provider を次の三つの単位で説明できるようになることです。
Provider
OCI の CRD と controller を Kubernetes cluster に追加する
ProviderConfig
どの資格情報で OCI API を呼ぶかを決める
Managed Resource
Bucket など、OCI resource に対応する Kubernetes resource
Bucket demo で見るべき順番は、次の通りです。
1. Crossplane core が動いている
2. OCI Provider が HEALTHY になっている
3. Secret に OCI credentials が入っている
4. ProviderConfig が Secret を参照している
5. Bucket YAML が正しい ProviderConfig を参照している
6. READY / SYNCED / EXTERNAL-NAME を見る
7. OCI Console で namespace、compartment、Bucket name を確認する
8. 削除は Managed Resource から行う
この順番で見ると、どこで詰まっているかを切り分けやすくなります。
まず Crossplane core を用意する
OCI Provider を入れる前に、Crossplane core が Kubernetes cluster 上で動いている必要があります。
最初に確認するのは、kubectl が正しい cluster を向いているかです。
kubectl config current-context
そのうえで、Crossplane 用の namespace を作り、Helm で Crossplane を install します。
kubectl create namespace crossplane-system
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane \
--namespace crossplane-system \
crossplane-stable/crossplane
install したら、crossplane-system の中で controller が起動しているかを見ます。
kubectl get all -n crossplane-system
ここで大事なのは、OCI Provider の問題を見る前に、土台である Crossplane core の起動を確認することです。
kubectl context が違う cluster を向いていると、以降の Provider、Secret、ProviderConfig、Bucket の確認がすべてずれてしまいます。
OCI Provider は family provider を先に入れる
OCI Provider では、まず provider-family を入れ、その後に Object Storage などの service provider を入れる流れになります。
公式 quickstart でも、family provider を先に install することが重要だと説明されています。
理由は、service provider が family provider に依存するためです。
service provider を先に入れると、package manager が依存関係を解決しようとして、意図しない family provider image を pull する可能性があります。
Object Storage Bucket demo では、最低限次の二つを入れます。
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: oracle-provider-family-oci
spec:
package: ghcr.io/oracle/provider-family-oci:<tag>
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-oci-objectstorage
spec:
package: ghcr.io/oracle/provider-oci-objectstorage:<tag>
<tag> は実際に使う release に合わせます。
古い記事や手元の manifest をそのまま使うのではなく、公式 repo の docs/quickstart.md と release を見て確認してください。
apply したら、Provider の状態を確認します。
kubectl get providers
見る列は、INSTALLED と HEALTHY です。
NAME INSTALLED HEALTHY
oracle-provider-family-oci True True
provider-oci-objectstorage True True
HEALTHY=True になるまで数分かかることがあります。
ここが False や空欄のままなら、ProviderConfig や Bucket YAML へ進む前に、ProviderRevision、package image、registry、network、pull secret を確認します。
認証情報は Secret に閉じ込める
OCI Provider が OCI API を呼ぶには、認証情報が必要です。
公式 quickstart では、主に次の認証方式が紹介されています。
API Key Authentication
Instance Principal Authentication
Workload Identity Authentication
手元で動きを理解する demo では、API Key Authentication が一番追いやすいです。
API Key の場合、tenancy OCID、user OCID、private key、fingerprint、region、auth type を credentials として Secret に入れます。
kubectl create secret generic oci-creds \
--namespace=crossplane-system \
--from-literal=credentials='{
"tenancy_ocid": "REPLACE_WITH_YOUR_TENANCY_OCID",
"user_ocid": "REPLACE_WITH_YOUR_USER_OCID",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nREPLACE_WITH_YOUR_KEY_CONTENT\n-----END RSA PRIVATE KEY-----\n",
"fingerprint": "REPLACE_WITH_YOUR_FINGERPRINT",
"region": "REPLACE_WITH_YOUR_REGION",
"auth": "ApiKey"
}'
ここで詰まりやすいのは、private key の改行です。
JSON の中に入れるため、改行は \n として扱います。
また、OCI CLI で生成した key に追加行が含まれている場合は、その行も同じ private_key の中に含め、改行を崩さないようにします。
この Secret は Kubernetes 側の credential 入れ物です。
OCI 側の IAM policy は別途必要です。
YAML が正しくても、OCI IAM で許可されていなければ Bucket 作成は失敗します。
ProviderConfig は Secret を OCI Provider に渡す入口
次に、ProviderConfig を作ります。
ProviderConfig は、Provider がどの credentials を使って OCI API を呼ぶかを決める resource です。
ここで少し混乱しやすいのが、legacy resource と modern namespaced resource の違いです。
公式 quickstart では、次のように整理されています。
| 対象 | ProviderConfig |
|---|---|
*.oci.upbound.io |
cluster-scoped ProviderConfig.oci.upbound.io
|
*.oci.m.upbound.io |
既定では ClusterProviderConfig.oci.m.upbound.io
|
| namespace ごとに認証を分けたい場合 | namespaced ProviderConfig.oci.m.upbound.io
|
まず cluster-wide に使う設定を作る場合は、次のように Secret を参照します。
apiVersion: oci.m.upbound.io/v1beta1
kind: ClusterProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
name: oci-creds
namespace: crossplane-system
key: credentials
legacy cluster-scoped resource を使う場合は、oci.upbound.io/v1beta1 の ProviderConfig も必要になります。
apiVersion: oci.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
name: oci-creds
namespace: crossplane-system
key: credentials
team ごとに credential を分けたい場合は、namespaced ProviderConfig.oci.m.upbound.io を使います。
apiVersion: oci.m.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
namespace: team-a
spec:
credentials:
source: Secret
secretRef:
name: oci-creds
namespace: team-a
key: credentials
初学者向けには、最初からすべてを覚える必要はありません。
まずは次の関係だけ押さえると十分です。
Secret
OCI credentials を持つ
ProviderConfig / ClusterProviderConfig
Secret を参照する
Bucket
providerConfigRef で使う ProviderConfig を選ぶ
Bucket YAML は三点だけ読む
次に、Object Storage Bucket の Managed Resource を作ります。
最初は YAML 全体を細かく読むより、次の三点だけを見ると理解しやすいです。
apiVersion / kind
spec.forProvider
providerConfigRef
modern namespaced resource の例として、概念を読みやすくした YAML は次の形です。
apiVersion: objectstorage.oci.m.upbound.io/v1alpha1
kind: Bucket
metadata:
name: bucket1
namespace: team-a
spec:
forProvider:
compartmentId: REPLACE_WITH_COMPARTMENT_OCID
name: bucket1
namespace: REPLACE_WITH_OBJECT_STORAGE_NAMESPACE
providerConfigRef:
kind: ProviderConfig
name: default
metadata.namespace は、Kubernetes 側でこの Managed Resource を置く namespace です。
spec.forProvider.namespace は、OCI Object Storage の namespace です。
同じ namespace という名前でも、意味が違います。
ここは demo でも間違えやすいポイントです。
公式 example では、compartmentId を直接書く代わりに compartmentIdSelector を使う例もあります。
spec:
forProvider:
compartmentIdSelector:
matchLabels:
testing.upbound.io/example-name: compartment_label_1
Selector を使うと、別の Managed Resource から値を参照できます。
ただし、最初の Bucket demo では、まず compartmentId、Bucket name、Object Storage namespace、providerConfigRef の対応を見るのが分かりやすいです。
apply は開始点で、作成は Provider の reconcile が行う
Bucket YAML を apply すると、すぐに OCI API が直接呼ばれるように見えるかもしれません。
実際には、流れは次のようになります。
kubectl apply
-> Kubernetes API Server に Bucket resource が保存される
-> OCI Provider が Bucket resource を observe する
-> ProviderConfig から credentials を読む
-> OCI API を呼ぶ
-> status に結果を書く
つまり、kubectl apply は開始点です。
実際の作成、更新、状態確認は、Provider の reconcile loop が行います。
ここは Crossplane を Terraform のような一回実行の CLI として見ないために重要です。
Crossplane では、resource が Kubernetes API に残っている間、Provider が継続的に状態を見ます。
成功判定は READY / SYNCED / EXTERNAL-NAME
Bucket を apply した後は、状態を確認します。
kubectl get managed --all-namespaces
kubectl get bucket.objectstorage.oci.m.upbound.io -A
見る列は、READY、SYNCED、EXTERNAL-NAME です。
NAMESPACE NAME READY SYNCED EXTERNAL-NAME
team-a bucket.objectstorage.oci.m.upbound.io/bucket1 True True n/<namespace>/b/bucket1
READY=True は、resource が利用可能な状態に近いことを示します。
SYNCED=True は、Provider の reconcile が成功していることを示します。
EXTERNAL-NAME は、Kubernetes resource と外部 OCI resource を対応づける名前です。
OCI Object Storage Bucket では、n/<namespace>/b/<bucket> のような形で表示されます。
ここまで見えたら、次は OCI Console でも確認します。
OCI Console では、Bucket name だけでなく、Object Storage namespace、compartment、region も合わせて確認します。
Kubernetes 側と OCI 側を対応づけるときは、次の四つを並べて見ると分かりやすいです。
metadata.name
spec.forProvider.name
spec.forProvider.namespace
EXTERNAL-NAME
READY / SYNCED が False のときは describe を見る
READY や SYNCED が False、または空欄のままなら、kubectl describe を見ます。
kubectl describe bucket.objectstorage.oci.m.upbound.io bucket1 -n team-a
特に見る場所は、Status.Conditions と Events です。
たとえば、ProviderConfig の参照が間違っている場合は、次のような方向の message が出ます。
cannot get referenced ProviderConfig
ProviderConfig ... "default" not found
この場合、Bucket の spec.providerConfigRef.name と、ProviderConfig の metadata.name が一致しているかを確認します。
また、legacy resource と modern namespaced resource を混ぜている場合も注意が必要です。
legacy:
objectstorage.oci.upbound.io
ProviderConfig.oci.upbound.io
modern namespaced:
objectstorage.oci.m.upbound.io
ClusterProviderConfig.oci.m.upbound.io
ProviderConfig.oci.m.upbound.io
ProviderConfig が正しくても、Secret の namespace、Secret の key、private key の改行、OCI IAM policy が原因で失敗することもあります。
describe は、次にどこを見るべきかを決めるための入口です。
demo では成功画面だけでなく、判断材料を見せる
Bucket demo を見せるときは、単に「作れました」で終わらせない方が理解しやすいです。
見せる順番は、次のようにすると自然です。
1. Provider が HEALTHY
2. Secret が存在する
3. ProviderConfig が Secret を参照している
4. Bucket YAML を apply する
5. kubectl get で READY / SYNCED / EXTERNAL-NAME を見る
6. 必要なら kubectl describe で conditions / events を見る
7. OCI Console で Bucket name、namespace、compartment を確認する
この順番にすると、Crossplane の責任範囲と OCI 側の実体がつながって見えます。
特に、READY / SYNCED と OCI Console を両方見るのがポイントです。
Kubernetes 側の状態だけではなく、外部 resource が本当に OCI 側にあることを確認できます。
初学者が詰まりやすい四か所
OCI Provider の Bucket demo では、詰まりやすい場所がだいたい決まっています。
一つ目は、version と apiVersion です。
provider release によって API group や field が変わる可能性があるため、古い manifest をそのまま使わないようにします。
二つ目は、scope です。
*.oci.upbound.io と *.oci.m.upbound.io では、ProviderConfig の見方が変わります。
三つ目は、Secret です。
Secret の namespace、key、private key の改行が違うと、ProviderConfig は存在していても認証に失敗します。
四つ目は、OCI IAM です。
Kubernetes 側の YAML が正しくても、OCI 側で compartment に対する権限がなければ作成できません。
この四つを先に知っておくと、demo で失敗しても落ち着いて切り分けられます。
削除は Managed Resource から行う
最後に削除です。
ここで大事なのは、Provider を先に消さないことです。
Provider は controller でもあります。
Managed Resource が残っている状態で Provider を消すと、削除や状態合わせを行う controller がいなくなり、後片付けが難しくなることがあります。
順番は、まず Bucket などの Managed Resource からです。
kubectl delete -f examples/namespaced/objectstorage/v1alpha1/bucket.yaml
kubectl get bucket.objectstorage.oci.m.upbound.io -A
Bucket が消えたことを確認してから、Provider 関連を削除します。
kubectl delete providers/provider-oci-objectstorage
# 作成した ProviderConfig / ClusterProviderConfig を削除する
kubectl delete clusterproviderconfig.oci.m.upbound.io/default
kubectl delete providerconfig.oci.upbound.io/default
kubectl delete providerconfig.oci.m.upbound.io/default -n team-a
kubectl delete providers/oracle-provider-family-oci
上の ProviderConfig / ClusterProviderConfig は、実際に作成したものだけ削除します。
実運用では、削除が本当に外部 OCI resource まで消す操作なのか、あるいは Kubernetes 側の管理だけ外す操作なのかを事前に確認します。
特に managementPolicies や deletionPolicy を使う場合は、どの操作を controller に許可しているかを確認してください。
まとめ
今回は、OCI Provider の構成、認証、Bucket demo を一つの流れとして整理しました。
覚える単位は、次の三つです。
Provider
CRD と controller を追加する
ProviderConfig
OCI credentials への参照を持つ
Managed Resource
Bucket などの OCI resource を Kubernetes resource として表す
Bucket demo の順番は、次のように見ると分かりやすいです。
Crossplane core
-> family provider
-> service provider
-> Secret
-> ProviderConfig
-> Bucket YAML
-> READY / SYNCED
-> OCI Console
-> delete
この一周を理解すると、OCI Provider を単なる YAML collection ではなく、Kubernetes API と OCI API をつなぐ controller として見られるようになります。
次は、この流れを既存 OCI resource の取り込み、Observe-only、Platform API、GitOps の観点へ広げて見ていきます。