Oracle Service Operator for Kubernatesを使用したMySQL Database Serviceの利用
先日、Oracle Service Operator for Kubernates(OSOK)のリリースが発表されました。
OSOKは、OCIが提供するデータベースサービス(Autonomous Database/MySQL Database Service)、ストリーミングサービスのためのKubernates Operator及びSDKとなります。
現時点でサポートされているサービスは以下になります。
- Autonomous Database (specifically Autonomous Transaction Processing, Autonomous Data Warehouse), which provides automated patching, upgrades, and tuning. Autonomous Database can perform all routine database maintenance tasks while the system is running, without human intervention.
- MySQL Database, which provides a fully managed database service for developing and deploying secure cloud native applications using the popular MySQL open source database.
- Streaming, which provides a fully managed, scalable, and durable solution for ingesting and consuming high-volume data streams in real-time
今回は、このOSOKを使用してMySQL Database ServiceをKubernatesのリソースとして動作させてみたいと思います。
Adding OCI Service Operator for Kubernetes to Clusters
OSOKの準備
OSOKを動作させるためには、以下を準備する必要があります。
- Oracle Cloud Infrastructureの利用準備
- Oracle Container Engine for Kubernetes(OKE)の作成
- 操作端末上へのkubectlのインストールと準備
- Operator SDKのインストール
- Operator Lifecycle Managerのインストール
- Oracle Service Operator for Kubernates に必要なクラウドリソースの作成
- Oracle Service Operator for Kubernates のインストール
- OKE上でのOCIサービスの作成
今回は、1~3については事前に対応済みとして、以降の作業から説明します。
1~3の準備につきましては、以下のマニュアルをご確認ください。
https://docs.oracle.com/ja-jp/iaas/Content/GSG/Concepts/baremetalintro.htm
https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Concepts/contengprerequisites.htm
Operator SDKのインストール
OSOKは、Kubernates上でOCIサービスを管理するためのOperatorです。
Operator Lifecycle Managerで管理できるようパッケージングされており、Operator SDKを使用して簡単にOKE上にデプロイできます。
Installationに従い、準備を進めていきます。
まずは、作業端末にoperator-sdkをダウンロードします。
今回は、WSL2(Ubuntu)で作業を行いました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
$ export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac) $ export OS=$(uname | awk '{print tolower($0)}') $ export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.11.0 $ curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH} $ gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E gpg: key 052996E2A20B5C7E: public key "Operator SDK (release) <cncf-operator-sdk@cncf.io>" imported gpg: Total number processed: 1 gpg: imported: 1 $ curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 621 100 621 0 0 2352 0 --:--:-- --:--:-- --:--:-- 2352 100 1399 100 1399 0 0 2786 0 --:--:-- --:--:-- --:--:-- 2786 $ curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 625 100 625 0 0 2422 0 --:--:-- --:--:-- --:--:-- 2422 100 566 100 566 0 0 1136 0 --:--:-- --:--:-- --:--:-- 2368 $ gpg -u "Operator SDK (release) <cncf-operator-sdk@cncf.io>" --verify checksums.txt.asc gpg: assuming signed data in 'checksums.txt' gpg: Signature made Thu Aug 12 09:02:46 2021 JST gpg: using RSA key 8613DB87A5BA825EF3FD0EBE2A859D08BF9886DB gpg: Good signature from "Operator SDK (release) <cncf-operator-sdk@cncf.io>" [unknown] gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: 3B2F 1481 D146 2380 80B3 46BB 0529 96E2 A20B 5C7E Subkey fingerprint: 8613 DB87 A5BA 825E F3FD 0EBE 2A85 9D08 BF98 86DB $ grep operator-sdk_${OS}_${ARCH} checksums.txt | sha256sum -c - operator-sdk_linux_amd64: OK $ chmod +x operator-sdk_${OS}_${ARCH} && sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk $ operator-sdk version operator-sdk version: "v1.11.0", commit: "28dcd12a776d8a8ff597e1d8527b08792e7312fd", kubernetes version: "1.20.2", go version: "go1.16.7", GOOS: "linux", GOARCH: "amd64" |
operator-sdkコマンドの実行準備ができたら、OLMをOKEにインストールします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
$ operator-sdk olm install INFO[0003] Fetching CRDs for version "latest" INFO[0003] Fetching resources for resolved version "latest" I0906 15:52:04.897711 3424381 request.go:668] Waited for 1.0370203s due to client-side throttling, not priority and fairness, request: GET:https://150.230.101.101:6443/apis/apiregistration.k8s.io/v1beta1?timeout=32s INFO[0020] Creating CRDs and resources INFO[0020] Creating CustomResourceDefinition "catalogsources.operators.coreos.com" INFO[0020] Creating CustomResourceDefinition "clusterserviceversions.operators.coreos.com" INFO[0020] Creating CustomResourceDefinition "installplans.operators.coreos.com" INFO[0020] Creating CustomResourceDefinition "operatorconditions.operators.coreos.com" INFO[0020] Creating CustomResourceDefinition "operatorgroups.operators.coreos.com" INFO[0020] Creating CustomResourceDefinition "operators.operators.coreos.com" INFO[0020] Creating CustomResourceDefinition "subscriptions.operators.coreos.com" INFO[0020] Creating Namespace "olm" INFO[0020] Creating Namespace "operators" INFO[0021] Creating ServiceAccount "olm/olm-operator-serviceaccount" INFO[0021] Creating ClusterRole "system:controller:operator-lifecycle-manager" INFO[0021] Creating ClusterRoleBinding "olm-operator-binding-olm" INFO[0021] Creating Deployment "olm/olm-operator" INFO[0021] Creating Deployment "olm/catalog-operator" INFO[0021] Creating ClusterRole "aggregate-olm-edit" INFO[0021] Creating ClusterRole "aggregate-olm-view" INFO[0022] Creating OperatorGroup "operators/global-operators" INFO[0026] Creating OperatorGroup "olm/olm-operators" INFO[0026] Creating ClusterServiceVersion "olm/packageserver" INFO[0026] Creating CatalogSource "olm/operatorhubio-catalog" INFO[0027] Waiting for deployment/olm-operator rollout to complete INFO[0027] Waiting for Deployment "olm/olm-operator" to rollout: 0 of 1 updated replicas are available INFO[0038] Deployment "olm/olm-operator" successfully rolled out INFO[0038] Waiting for deployment/catalog-operator rollout to complete INFO[0038] Waiting for Deployment "olm/catalog-operator" to rollout: 0 of 1 updated replicas are available INFO[0043] Deployment "olm/catalog-operator" successfully rolled out INFO[0043] Waiting for deployment/packageserver rollout to complete INFO[0043] Waiting for Deployment "olm/packageserver" to rollout: 0 of 2 updated replicas are available INFO[0048] Deployment "olm/packageserver" successfully rolled out INFO[0048] Successfully installed OLM version "latest" NAME NAMESPACE KIND STATUS catalogsources.operators.coreos.com CustomResourceDefinition Installed clusterserviceversions.operators.coreos.com CustomResourceDefinition Installed installplans.operators.coreos.com CustomResourceDefinition Installed operatorconditions.operators.coreos.com CustomResourceDefinition Installed operatorgroups.operators.coreos.com CustomResourceDefinition Installed operators.operators.coreos.com CustomResourceDefinition Installed subscriptions.operators.coreos.com CustomResourceDefinition Installed olm Namespace Installed operators Namespace Installed olm-operator-serviceaccount olm ServiceAccount Installed system:controller:operator-lifecycle-manager ClusterRole Installed olm-operator-binding-olm ClusterRoleBinding Installed olm-operator olm Deployment Installed catalog-operator olm Deployment Installed aggregate-olm-edit ClusterRole Installed aggregate-olm-view ClusterRole Installed global-operators operators OperatorGroup Installed olm-operators olm OperatorGroup Installed packageserver olm ClusterServiceVersion Installed operatorhubio-catalog olm CatalogSource Installed |
Oracle Service Operator for Kubernates に必要なクラウドリソースの作成
OSOKでは、OperatorからOCIサービスを管理するためにAPIコールを実行します。
そのため、OKEのワーカノードからリソースの管理のためのAPIコールを許可する必要があります。
まずはOKE用のDynamic Groupを作成してください。
1 2 3 4 |
$ oci iam dynamic-group create -c <tenancy ocid> \ --name "osok-dynamic-group" \ --matching-rule "Any {instance.compartment.id = '<OKE compartment ocid>'}" \ --description "for osok" |
Dynamic Groupには以下のポリシが必要です。
1 2 3 4 |
$ oci iam policy create -c <tenancy ocid> \ --name "osok-dynamic-group-policy" \ --description "for osok" \ --statements '["Allow dynamic-group osok-dynamic-group to {SUBNET_READ, SUBNET_ATTACH, SUBNET_DETACH, VCN_READ, COMPARTMENT_INSPECT} in compartment <OKE compartment name>","Allow dynamic-group osok-dynamic-group to manage mysql-family in compartment <OKE compartment name>"]' |
また、OSOKが利用するOCIユーザ/グループの作成も必要となります。
作成後に表示されるユーザ、グループのOCIDはOSOKのSecretに利用するため記憶しておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ oci iam user create -c <tenancy ocid> \ --name osok-user \ --description "for osok" $ oci iam group create -c <tenancy ocid> \ --name osok-operator-group \ --description "for osok" $ oci iam group add-user \ --group-id <osok-operator-group ocid> \ --user-id <osok-user ocid> |
作成したユーザのAPI Keyを準備します。
1 2 3 4 5 |
$ openssl genrsa -out ~/.oci/osok_api_key.pem 2048 $ chmod go-rwx ~/.oci/osok_api_key.pem $ openssl rsa -pubout -in ~/.oci/osok_api_key.pem -out ~/.oci/osok_api_key_public.pem $ openssl rsa -pubout -outform DER -in ~/.oci/osok_api_key.pem | openssl md5 -c # 出力されたfingerprintを記録 $ oci iam user api-key upload --user-id <osok user ocid> --key-file ~/.oci/osok_api_key_public.pem |
Oracle Service Operator for Kubernates のインストール
デフォルトのNamespaceでも問題ありませんが、ここでは検証に利用するNamespaceを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ cat ns.yaml apiVersion: v1 kind: Namespace metadata: labels: control-plane: controller-manager name: oci-service-operator-system $ kubectl apply -f ns.yaml namespace/oci-service-operator-system created $ kubectl config set-context --current --namespace=oci-service-operator-system |
OSOKが利用するためのSecretsを作成します。
1 2 3 4 5 6 |
$ kubectl -n oci-service-operator-system create secret generic ocicredentials \ --from-literal=tenancy=<tenancy ocid> \ --from-literal=user=<osok user ocid> \ --from-literal=fingerprint=<api key fingerprint> \ --from-literal=region=<region> \ --from-file=privatekey=<api private key path> |
Operator Bundle ImageをPullし、operator-sdk でインストールします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ docker pull iad.ocir.io/oracle/oci-service-operator-bundle:1.0.0 $ operator-sdk run bundle iad.ocir.io/oracle/oci-service-operator-bundle:1.0.0 INFO[0019] Successfully created registry pod: iad-ocir-io-oracle-oci-service-operator-bundle-1-0-0 INFO[0019] Created CatalogSource: oci-service-operator-catalog INFO[0020] OperatorGroup "operator-sdk-og" created INFO[0020] Created Subscription: oci-service-operator-v1-0-0-sub INFO[0025] Approved InstallPlan install-4vc77 for the Subscription: oci-service-operator-v1-0-0-sub INFO[0025] Waiting for ClusterServiceVersion "default/oci-service-operator.v1.0.0" to reach 'Succeeded' phase INFO[0025] Waiting for ClusterServiceVersion "default/oci-service-operator.v1.0.0" to appear INFO[0047] Found ClusterServiceVersion "default/oci-service-operator.v1.0.0" phase: Pending INFO[0048] Found ClusterServiceVersion "default/oci-service-operator.v1.0.0" phase: Installing INFO[0070] Found ClusterServiceVersion "default/oci-service-operator.v1.0.0" phase: Succeeded INFO[0070] OLM has successfully installed "oci-service-operator.v1.0.0" |
インストールが完了すると、OSOKの各リソースが作成されている事が確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ kubectl get all NAME READY STATUS RESTARTS AGE pod/iad-ocir-io-oracle-oci-service-operator-bundle-1-0-0 1/1 Running 0 18h pod/oci-service-operator-controller-manager-799dfc795d-jnkv4 1/1 Running 0 18h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/oci-service-operator-controller-manager 1/1 1 1 18h NAME DESIRED CURRENT READY AGE replicaset.apps/oci-service-operator-controller-manager-799dfc795d 1 1 1 18h $ kubectl get operators NAME AGE oci-service-operator.default 18h |
OKE上でのMySQL Database Serviceの作成
OSOKを使用して作成できるリソースは個別にドキュメントが用意されています。
ここではMySQL Database Service(MDS)を作成したいと思います。
まずは、MDSに利用する管理ユーザ名、パスワードのSecretを作成します。
Secretsに指定する文字列はbase64でハッシュされている必要があります。
1 2 3 4 |
$ echo -n admin | base64 YWRtaW4K $ echo -n P@ssw0rd | base64 UEBzc3cwcmQK |
以下の内容で、secret.yamlを作成しました。
1 2 3 4 5 6 7 8 |
apiVersion: v1 kind: Secret metadata: name: mds-secret type: Opaque data: username: YWRtaW4= password: UEBzc3cwcmQ= |
次にMySQL Database System用のマニフェストを作成します。
マニフェストに指定可能なパラメータは以下を参照してください。
configration.id
、shapeName
は以下で確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ oci mysql configuration list --all | jq '.data[]|[."shape-name",."id"]' [ "BM.Standard.E2.64", "ocid1.mysqlconfiguration.oc1..aaaaaaaah6o6qu3gdbxnqg6aw56amnosmnaycusttaa7abyq2tdgpgubvsgh" ] [ "VM.Standard.E2.1", "ocid1.mysqlconfiguration.oc1..aaaaaaaah6o6qu3gdbxnqg6aw56amnosmnaycusttaa7abyq2tdgpgubvsgi" ] [ "VM.Standard.E2.2", "ocid1.mysqlconfiguration.oc1..aaaaaaaah6o6qu3gdbxnqg6aw56amnosmnaycusttaa7abyq2tdgpgubvsgj" ] : |
今回は、以下のように mds.yaml
を作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
apiVersion: oci.oracle.com/v1beta1 kind: MySqlDbSystem metadata: name: mds labels: app: mysqldbsystem spec: compartmentId: <compartment ocid> displayName: "MySQL Database Service" shapeName: MySQL.VM.Standard.E3.1.8GB subnetId: <MDS Subnet ocid> configuration: id: <Configration ocid> availabilityDomain: OSrA:AP-TOKYO-1-AD-1 adminUsername: secret: secretName: mds-secret adminPassword: secret: secretName: mds-secret description: "MySQL Database Service" dataStorageSizeInGBs: 100 port: 3306 portX: 33060 hostnameLabel: mysqldbsystem freeformTags: Name: "MDS" |
これまでに作成したマニフェストを実行します。
1 2 |
$ kubectl apply -f secert.yaml $ kubectl apply -f mds.yaml |
しばらくすると、MDSが作成されている事が確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
$ kubectl get mysqldbsystem NAME STATUS AGE mds-db-system Active 18h $ kubectl describe mysqldbsystems Name: mds Namespace: oci-service-operator-system Labels: app=mysqldbsystem Annotations: <none> API Version: oci.oracle.com/v1beta1 Kind: MySqlDbSystem Metadata: Creation Timestamp: 2021-09-06T08:23:18Z : (略) : Spec: Admin Password: Secret: Secret Name: mds-secret Admin Username: Secret: Secret Name: mds-secret Availability Domain: OSrA:AP-TOKYO-1-AD-1 Backup Policy: Compartment Id: ocid1.compartment.oc1..aaaaaaaany2sftbhhbbcirt6zoelmfbubshnowy46ixt42ahtz2wcuo4sl2a Configuration: Id: ocid1.mysqlconfiguration.oc1..aaaaaaaalwzc2a22xqm56fwjwfymixnulmbq3v77p5v4lcbb6qhkftxf2trq Data Storage Size In G Bs: 100 Description: MySQL Database Service Display Name: MySQL Database Service Fault Domain: FAULT-DOMAIN-1 Freeform Tags: Name: MDS Maintenance: Port: 3306 Port X: 33060 Shape Name: MySQL.VM.Standard.E3.1.8GB Source: Subnet Id: ocid1.subnet.oc1.ap-tokyo-1.aaaaaaaaly7luc3q6lwdv7tiqn6vghsejwg33qs6cdtl3gs6mp2znpdopnqa Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Success 12s MySqlDbSystem Finalizer is added to the object |
接続テスト用のPodをデプロイします。
1 2 3 4 5 6 7 8 |
$ kubectl run test-mysql --image=mysql:8.0.26 --restart=Never --env="MYSQL_ALLOW_EMPTY_PASSWORD=yes" pod/test-mysql created $ kubectl get pods test-mysql NAME READY STATUS RESTARTS AGE test-mysql 1/1 Running 0 46s $ kubectl logs test-mysql | tail : 2021-09-06T08:34:11.832929Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.26' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL. |
MDSの接続情報はSecretとして格納されていますので、以下のように確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$ kubectl describe secret mds Name: mds Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== AvailabilityDomain: 20 bytes Endpoints: 137 bytes FaultDomain: 14 bytes InternalFQDN: 0 bytes MySQLPort: 4 bytes MySQLXProtocolPort: 5 bytes PrivateIPAddress: 12 bytes $ kubectl get secret mds -o jsonpath="{.data.Endpoints}" | base64 --decode [{"ipAddress":"192.168.0.44","port":3306,"portX":33060,"hostname":null,"modes":["READ","WRITE"],"status":"ACTIVE","statusDetails":null}] |
確認したIP/PORT、及び設定した接続情報でアクセスできることを確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ kubectl exec test-mysql -it -- mysql -uadmin -p -h192.168.0.44 Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 231 Server version: 8.0.26-u1-cloud MySQL Enterprise - Cloud Copyright (c) 2000, 2021, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> |
問題なくアクセスできる事が確認できました!
なお、内部FQDNでももちろんアクセス可能ですが、弊社検証時にはFQDNが有効であってもSecretに表示されませんでした。
1 2 3 4 5 6 7 8 9 10 |
$ kubectl get secret mds -o jsonpath="{.data}" | jq . { "AvailabilityDomain": "T1NyQTpBUC1UT0tZTy0xLUFELTE=", "Endpoints": "W3siaXBBZGRyZXNzIjoiMTkyLjE2OC4wLjQ0IiwicG9ydCI6MzMwNiwicG9ydFgiOjMzMDYwLCJob3N0bmFtZSI6bnVsbCwibW9kZXMiOlsiUkVBRCIsIldSSVRFIl0sInN0YXR1cyI6IkFDVElWRSIsInN0YXR1c0RldGFpbHMiOm51bGx9XQo=", "FaultDomain": "RkFVTFQtRE9NQUlOLTE=", "InternalFQDN": "", "MySQLPort": "MzMwNg==", "MySQLXProtocolPort": "MzMwNjA=", "PrivateIPAddress": "MTkyLjE2OC4wLjQ0" } |
実運用では、Serviceリソースを定義することで接続先の切り替えが容易になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
$ cat service.yaml --- kind: Service apiVersion: v1 metadata: name: db-service spec: clusterIP: None ports: - port: 3306 name: mysql - port: 33060 name: mysqlx --- kind: Endpoints apiVersion: v1 metadata: name: db-service subsets: - addresses: - ip: 192.168.0.44 ports: - port: 3306 name: mysql - port: 33060 name: mysqlx $ kubectl apply -f service.yaml |
Kubernatesのサービスからもアクセス可能なことが確認できました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ kubectl exec test-mysql -it -- mysql -uadmin -p -hdb-service.oci-service-operator-system.svc.cluster.local Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 231 Server version: 8.0.26-u1-cloud MySQL Enterprise - Cloud Copyright (c) 2000, 2021, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> |
まとめ
OSOKを利用した、OCIのデータベースサービスとKubernatesの統合について見ていきました。
前準備が少々ありますが、とても簡単にリソースを登録することができました。
Kubernatesにおけるデータベースのようなステートフルなアプリケーションの運用は悩みのタネですが、MDSやADBのようなマネージドサービスを利用することで、安心してアプリケーションの開発に注力できるのではないでしょうか。
現時点では、MDSに関してはHeatwaveの有効化や、バックアップの設定といった項目は無いようですが、今後さらに機能が拡張されていく事を期待したいと思います。
Kubernatesを導入されている方は、ぜひご検討ください。