はじめに
今回はOracleの分散データベースであるOracle Globally Distributed AI Database(以下 GDD)を Oracle Kubernetes Engine(OKE)上に構築し、Raft replicationを使った 3 shard構成で作ってみました。
Oracle Globally Distributed AI Databaseとは
Oracle Globally Distributed AI Databaseは、データをOracle Databaseのインスタンスをシャードとして、水平パーティショニングして分散させることで、スケーラビリティや高い可用性や障害分離、データの地理的分散といったメリットを享受できるPaaSサービスであり、Oracle AI Databaseの機能です。
全体のアーキテクチャはこの資料がわかりやすいです。
今回の構成
一応FD単位でも分散させることができそうでしたが、3ADで分散させたかったので、リージョンはAshburnを選択しました。
| 項目 | 値 |
|---|---|
| OCI region | us-ashburn-1 |
| OKE | Kubernetes v1.35.2
|
| Namespace | gdd-poc |
| Helm release | gdd-poc |
| Helm revision | 13 |
| Shard Catalog | 1 pod |
| Shard DB | 3 pods |
| GSM / Shard Director | 1 pod |
| GSM name | sharddirector2 |
| GSM port | 1523 |
| StorageClass | oci-bv |
| Replication Type | Native |
| Shard Type | System-managed |
構成イメージです。
Application
|
v
GSM / Shard Director
|
+--> Shard Catalog
|
+--> Shard 1 / AD1
+--> Shard 2 / AD2
+--> Shard 3 / AD3
事前に確認した公式情報
作業前に以下を確認しました。
- GDD 製品紹介ページ
- Using Raft Replication in Oracle Globally Distributed AI Database
- Deploy an Oracle Globally Distributed AI Database on Kubernetes
- Supported Versions of Kubernetes on OKE
- Provisioning PVCs on the Block Volume Service
- oracle/docker-images - OracleDatabase/GDD
- oracle/db-sharding - oke-based-sharding-deployment
Oracle公式docsでは、Raft replicationはGDDに組み込まれた replicationで、Data Guardの構成を必須にしないとのことでした(あくまでも私の理解の範囲ですが)。また、Raft replicationはsystem-managed data distributionで使う前提です。
1. OKE cluster / node poolを用意する
OKE cluster は v1.35.2 を使いました。
OKE v1.35 以降では cgroups v2 が重要になるため、worker node image OL8以降かつcgroups v2 対応のOKE imageを使います。
node poolは役割ごとに分けています。
pool-gdd-ad1 shard/catalog 用
pool-gdd-ad2 shard 用
pool-gdd-ad3 shard 用
pool-gsm GSM 用
node label は以下のようにしました。
gdd-role=shard
gdd-role=gsm
gdd-ad=ad1
gdd-ad=ad2
gdd-ad=ad3
oracleshard=ad1
oracleshard=ad2
oracleshard=ad3
oraclegsm=ogsm
確認コマンドです。
kubectl get nodes \
-L topology.kubernetes.io/zone,gdd-ad,gdd-role,oracleshard,oraclegsm
期待するイメージです。
NAME STATUS ZONE GDD-AD GDD-ROLE ORACLESHARD ORACLEGSM
<node-ad1> Ready US-ASHBURN-AD-1 ad1 shard ad1
<node-ad2> Ready US-ASHBURN-AD-2 ad2 shard ad2
<node-ad3> Ready US-ASHBURN-AD-3 ad3 shard ad3
<node-gsm1> Ready US-ASHBURN-AD-2 gsm ogsm
<node-gsm2> Ready US-ASHBURN-AD-3 gsm ogsm
2. StorageClassを確認する
今回はOracle AI DatabaseのデータをPodの中ではなく、Block Volumeに置くために、確認しています。
OKEのBlock Volume CSIを使います。
kubectl get storageclass
期待する結果のイメージです。
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
oci-bv (default) blockvolume.csi.oraclecloud.com Delete WaitForFirstConsumer
Helm values側では storageClassName: "oci-bv" を明示しました。
3. namespaceを作成する
kubectl create namespace gdd-poc
確認します。
kubectl get namespace gdd-poc
期待するイメージです。
NAME STATUS AGE
gdd-poc Active 10s
4. Oracle Container Registry用のimagePullSecretを作成する
Oracle Container RegistryからDB / GSM imageをpullするため、imagePullSecretを作成します。
kubectl create secret docker-registry oshardsecret \
--namespace gdd-poc \
--docker-server=container-registry.oracle.com \
--docker-username='<Oracle Account username>' \
--docker-password='<Auth Token>' \
--docker-email='<email>'
確認します。
kubectl get secret oshardsecret -n gdd-poc
期待するイメージです。
NAME TYPE DATA AGE
oshardsecret kubernetes.io/dockerconfigjson 1 1m
5. DB password用のSecretを作成する
DB password 関連は db-user-pass Secret に入れました。
kubectl create secret generic db-user-pass \
--namespace gdd-poc \
--from-file=common_os_pwdfile.enc=./common_os_pwdfile.enc \
--from-file=pwd.key=./pwd.key
確認します。
kubectl get secret db-user-pass -n gdd-poc
期待するイメージです。
NAME TYPE DATA AGE
db-user-pass Opaque 2 1m
6. Oracle公式GitHubのリポジトリを取得する
今回参照した公式GitHubのリポジトリは以下です。
mkdir -p ~/gdd-poc/work/upstream
cd ~/gdd-poc/work/upstream
git clone https://github.com/oracle/docker-images.git
git clone https://github.com/oracle/db-sharding.git
GDD scriptsは以下にあります。
ls ~/gdd-poc/work/upstream/docker-images/OracleDatabase/GDD/containerfiles/scripts
OKE用Helm chartは以下をベースにしています。
ls ~/gdd-poc/work/upstream/db-sharding/oke-based-sharding-deployment
7. GDD scriptsをConfigMap化する
Pod起動時に同じ構成を再現できるように、GitHubからscriptをpullするのではなく、固定したscriptsをConfigMapとして渡します。
SCRIPT_DIR="$HOME/gdd-poc/work/upstream/docker-images/OracleDatabase/GDD/containerfiles/scripts"
mkdir -p ~/gdd-poc/work/gdd-scripts-26ai
cp -R "$SCRIPT_DIR"/. ~/gdd-poc/work/gdd-scripts-26ai/
find ~/gdd-poc/work/gdd-scripts-26ai -type d -name "__pycache__" -prune -exec rm -rf {} +
find ~/gdd-poc/work/gdd-scripts-26ai -type f -name "*.pyc" -delete
kubectl create configmap gdd-scripts-26ai \
--namespace gdd-poc \
--from-file=~/gdd-poc/work/gdd-scripts-26ai \
--dry-run=client \
-o yaml > ~/gdd-poc/work/gdd-scripts-26ai-configmap.yaml
生成したYAMLを確認します。
grep -E "name: gdd-scripts-26ai|oragsm.py|main.py" \
~/gdd-poc/work/gdd-scripts-26ai-configmap.yaml
適用します。
kubectl apply -f ~/gdd-poc/work/gdd-scripts-26ai-configmap.yaml
確認します。
kubectl get configmap gdd-scripts-26ai -n gdd-poc
期待するイメージです。
NAME DATA AGE
gdd-scripts-26ai 16 1m
Configmapには、scriptだけを入れています。
8. DB / GSM imageをdigest固定する
今回使ったimageは以下です。
container-registry.oracle.com/database/enterprise
container-registry.oracle.com/database/gsm
こちらも同じimageを使って、再現性を高めるためにHelm valuesではdigest固定にしました。
global:
imagePullSecrets:
- name: oshardsecret
database:
image:
repository: container-registry.oracle.com/database/enterprise
digest: sha256:<db-image-digest>
gsm:
image:
repository: container-registry.oracle.com/database/gsm
digest: sha256:<gsm-image-digest>
9. Helm valuesの設定
今回のGSMは sharddirector2 / 1523 を正ルートにしています。
global:
scripts:
source: configMap
gsmports:
containerGSMPort: 1523
gsm:
replicaCount: 1
service:
port: 1523
env:
SHARD_DIRECTOR_PARAMS: "director_name=sharddirector2;director_region=region1;director_port=1523"
PVC は oci-bv を明示します。
storageClassName: "oci-bv"
10. Helm templateで事前確認する
いきなりinstallせずに、まずはmanifestをrenderします。
cd ~/gdd-poc/GDD-on-OKE/helm/gdd-poc
helm dependency build ./oracle-sharding-si-chart
helm template gdd-poc ./oracle-sharding-si-chart \
--namespace gdd-poc \
-f ./values-poc.yaml \
> ~/gdd-poc/work/helm-template-gdd-poc.yaml
確認ポイントです。
grep -E "container-registry.oracle.com/database/(enterprise|gsm)@sha256" \
~/gdd-poc/work/helm-template-gdd-poc.yaml
grep -E "storageClassName: \"oci-bv\"" \
~/gdd-poc/work/helm-template-gdd-poc.yaml
grep -E "containerGSMPort|1523|sharddirector2" \
~/gdd-poc/work/helm-template-gdd-poc.yaml
grep -E "codeload.github.com|dockerfiles/19.3.0|privileged: true|type: LoadBalancer" \
~/gdd-poc/work/helm-template-gdd-poc.yaml || true
期待すること:
- DB / GSM image が digest 固定で出る
- storageClassName が oci-bv
- GSM port が 1523
- sharddirector2 が出る
- codeload.github.com が出ない
- 古い dockerfiles/19.3.0 が出ない
- privileged: true が出ない
- 意図しない LoadBalancer が出ない
server-side dry-run も実施しました。
kubectl apply --dry-run=server \
-f ~/gdd-poc/work/helm-template-gdd-poc.yaml \
-n gdd-poc
11. Helm installする
helm install gdd-poc ./oracle-sharding-si-chart \
-f ./values-poc.yaml \
-n gdd-poc
確認します。
helm list -n gdd-poc
helm status gdd-poc -n gdd-poc
kubectl get pods,sts,svc -n gdd-poc -o wide
kubectl get pvc -n gdd-poc -o wide
期待するイメージです。
NAME NAMESPACE REVISION STATUS
gdd-poc gdd-poc 13 deployed
最終的には以下のようになりました。
gsm-0 1/1 Running
oshard-catalog-0 1/1 Running
oshard1-0 1/1 Running
oshard2-0 1/1 Running
oshard3-0 1/1 Running
PVCは以下です。
gdd-poc-oraclesharding Bound 50Gi RWO oci-bv
oshard-catalog-data Bound 50Gi RWO oci-bv
oshard1-data Bound 50Gi RWO oci-bv
oshard2-data Bound 50Gi RWO oci-bv
oshard3-data Bound 50Gi RWO oci-bv
12. GSMの起動確認
ここが大事で、gsm-0 が 1/1 Running でも、GSM listenerが起動しているとは限りません。
なので、起動を確認する必要があります。
kubectl exec -n gdd-poc gsm-0 -- sh -lc \
'ss -ltnp | grep -E "1522|1523|6123|6234|8080" || true'
kubectl exec -n gdd-poc gsm-0 -- sh -lc \
'ps -ef | grep -E "gsm|gds|tnslsnr" | grep -v grep || true'
成功時は 1523 が listen していました。
0.0.0.0:1523 LISTEN tnslsnr
GSM processも SHARDDIRECTOR2 として常駐していました。
SHARDDIRECTOR2
gsmmon
gsmoci
tnslsnr
gsmping
gsmopxy
gsmonsc
ons
GDSCTLに入ります。
kubectl exec -it -n gdd-poc gsm-0 -- bash
export ORACLE_HOME=/u01/app/oracle/product/23ai/gsmhome_1
export PATH="$ORACLE_HOME/bin:$PATH"
export TNS_ADMIN=/opt/oracle/gsmdata
gdsctl
GDSCTL内で確認します。
status gsm -gsm sharddirector2
成功時の確認ポイントです。
Connected to GDS catalog Y
Mastership Y
Regional Mastership TRUE
14. GDS catalogへ接続する
GDSCTL内でcatalogに接続します。
connect mysdbadmin@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oshard-catalog-0.oshard-catalog)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=CAT1PDB)))
確認します。
config sdb
期待する状態です。
Replication Type: Native
Shard type: System-managed
この時点では、まだshardが登録されていない場合があり、私の場合は空でした。
15. shardを手動登録する
今回は自動 setupが Gsm Setup is already completed on this database により skipされたので、GDS catalog上ではshardが未登録でした。
そのため、GDSCTLで1 shardずつ登録しました。
流れは以下です。
add cdb
config cdb
add shard
config shard
shard1
add cdb -connect oshard1-0.oshard1:1521/ORCL1CDB
次に config cdb でCDB名を確認します。
config cdb
orcl1cdb のようにlowercaseで表示された名前を、そのまま add shard -cdb に使います。
add shard -cdb orcl1cdb -connect "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oshard1-0.oshard1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL1PDB)(SERVER=DEDICATED)))" -shardgroup shardgroup1
shard2
add cdb -connect oshard2-0.oshard2:1521/ORCL2CDB
add shard -cdb orcl2cdb -connect "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oshard2-0.oshard2)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL2PDB)(SERVER=DEDICATED)))" -shardgroup shardgroup1
shard3
add cdb -connect oshard3-0.oshard3:1521/ORCL3CDB
add shard -cdb orcl3cdb -connect "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oshard3-0.oshard3)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL3PDB)(SERVER=DEDICATED)))" -shardgroup shardgroup1
注意点です。
add cdb -> GSMROOTUSER の password
add shard -> GSMUSER の password
-pwd は使わず、GDSCTLの対話入力でpasswordを扱いました。
16. deploy前の状態
3 shard登録後、かつdeploy前は以下の状態でした。
orcl1cdb_orcl1pdb shardgroup1 U none region1 -
orcl2cdb_orcl2pdb shardgroup1 U none region1 -
orcl3cdb_orcl3pdb shardgroup1 U none region1 -
この時点では databases は Registered: N、status ru と config chunks は空でした。
これは deploy前の正常状態として扱いました。
17. deployする
GDSCTL 内で deploy を 1 回実行します。
deploy
成功ログです。
deploy: examining configuration...
deploy: shards configured successfully
The operation completed successfully
18. deploy後の確認
config shard
config shard
成功時のログです。
orcl1cdb_orcl1pdb shardgroup1 Ok Deployed region1 ONLINE
orcl2cdb_orcl2pdb shardgroup1 Ok Deployed region1 ONLINE
orcl3cdb_orcl3pdb shardgroup1 Ok Deployed region1 ONLINE
databases -verbose
databases -verbose
成功時のログです。
orcl1cdb_orcl1pdb Registered: Y State: Ok ONS: N Role: SNR[RW] Instances: 1
orcl2cdb_orcl2pdb Registered: Y State: Ok ONS: N Role: SNR[RW] Instances: 1
orcl3cdb_orcl3pdb Registered: Y State: Ok ONS: N Role: SNR[RW] Instances: 1
status ru
status ru
成功時は RU 1-6 がすべて Ok になりました。
RU 1: Ok
RU 2: Ok
RU 3: Ok
RU 4: Ok
RU 5: Ok
RU 6: Ok
Leader 配置は以下でした。
orcl1cdb_orcl1pdb: RU 1, RU 4 Leader
orcl2cdb_orcl2pdb: RU 2, RU 5 Leader
orcl3cdb_orcl3pdb: RU 3, RU 6 Leader
status ru -show_chunks
status ru -show_chunks
RU 1: chunks 1-5
RU 2: chunks 6-10
RU 3: chunks 11-15
RU 4: chunks 16-20
RU 5: chunks 21-25
RU 6: chunks 26-30
status ru -show_errors
status ru -show_errors
成功時は errorは空でした。
ERRORS
------------------------
config chunks
config chunks
orcl1cdb_orcl1pdb 1 30
orcl2cdb_orcl2pdb 1 30
orcl3cdb_orcl3pdb 1 30
これで、3 shardすべてに chunks 1-30 が配置され、RU leaderも 3 shardに分散していることを確認できました。
19. Kubernetes側の最終確認
kubectl get pods -n gdd-poc -o wide
結果です。
gsm-0 1/1 Running AD2
oshard-catalog-0 1/1 Running AD1
oshard1-0 1/1 Running AD1
oshard2-0 1/1 Running AD2
oshard3-0 1/1 Running AD3
PVC も確認します。
kubectl get pvc -n gdd-poc -o wide
結果です。
gdd-poc-oraclesharding Bound 50Gi RWO oci-bv
oshard-catalog-data Bound 50Gi RWO oci-bv
oshard1-data Bound 50Gi RWO oci-bv
oshard2-data Bound 50Gi RWO oci-bv
oshard3-data Bound 50Gi RWO oci-bv
まとめ
Oracle Globally Distributed AI Database を OKE 上に構築し、3 shard / Raft replication の deploy 成功まで確認できました。
最終的には以下を確認できました。
config sdb: Replication Type Native / Shard type System-managed
config shard: 3 shard すべて Ok / Deployed / ONLINE
databases -verbose: 3 shard すべて Registered: Y / State: Ok
status ru: RU 1-6 すべて Ok
status ru -show_errors: error 空
config chunks: 3 shard すべて 1-30
shard pod: AD1 / AD2 / AD3 に分散
PVC: すべて Bound / oci-bv
かなり手探りでしたが、CodexとClaude Codeを使いながら何とか構築することができました。
まだ中にデータを入れていないので、次回はサンプルアプリケーションを用いた検証にもチャレンジできればと思います。