Important: Complete Installation first.
This quick start assumes OLM, the OSOK MySQL bundle, and OCI authentication are already installed and working in a test or non-production environment.
This example also requires kro. kro is not a general OSOK prerequisite, but it is required for this specific example because the walkthrough exposes the OSOK MySQL
DbSystembehind a singleOsokMysqlSystemAPI.
This quick start is a focused end-to-end example for users who want one concrete workflow from an installed controller to a provisioned OCI resource. It shows how to:
- confirm the OSOK MySQL installation path used for the example
- install kro for the example flow
- define an
OsokMysqlSystemAPI with aResourceGraphDefinition - create one
OsokMysqlSystemcustom resource - let kro and OSOK provision an OCI MySQL DB System
- verify the resulting connection Secret and clean the stack up
This guide intentionally stays narrow. Use Installation, MySQL DB Systems, and Supported Resources for the broader OSOK surface.
This example assumes you already have:
- a Kubernetes cluster in OCI, such as OKE, with
kubectlaccess helmandoperator-sdkinstalled locally- a test OCI environment where you can create Dynamic Groups, Policies, and MySQL DB Systems
- a private subnet that the MySQL DB System can use
- a MySQL configuration OCID that matches the MySQL shape and version you want to use
For this walkthrough, use the MySQL package bundle from Installation:
operator-sdk run bundle ghcr.io/<REPOSITORY_OWNER>/oci-service-operator-mysql-bundle:v2.0.0-alphaUse one of the authentication paths from Installation:
- Instance Principal when the cluster runs in OCI
- User Principal when the controller runs outside OCI
- Security Token when that matches your external-OCI workflow
For this example, the MySQL controller runs in the
oci-service-operator-mysql-system namespace.
Install kro with Helm:
helm install kro oci://registry.k8s.io/kro/charts/kro \
--namespace kro-system \
--create-namespaceVerify the installation:
kubectl get pods -n kro-system
kubectl get resourcegraphdefinitions.kro.runFor a pinned version or a raw-manifest install, use the official kro install guide: Installing kro.
This example assumes kro's default test-oriented install path. If you run kro
with stricter aggregated RBAC, grant kro access to the resources used here: the
generated OsokMysqlSystem instances, Secrets, and
dbsystems.mysql.oracle.com. See the official kro access-control guide:
Access Control.
This walkthrough assumes OSOK is running on OKE with Instance Principals.
Create a Dynamic Group that matches the Kubernetes worker nodes in the cluster compartment:
Any {instance.compartment.id = '<KUBERNETES_CLUSTER_COMPARTMENT_OCID>'}
Then create policies like:
Allow dynamic-group <OSOK_DYNAMIC_GROUP> to {SUBNET_READ, SUBNET_ATTACH, SUBNET_DETACH, VCN_READ, COMPARTMENT_INSPECT} in compartment id <COMPARTMENT_OCID>
Allow dynamic-group <OSOK_DYNAMIC_GROUP> to manage mysql-family in compartment id <COMPARTMENT_OCID>
Allow dynamic-group <OSOK_DYNAMIC_GROUP> to use tag-namespaces in tenancy
If you need broader scope, adapt those statements for tenancy-wide permissions. For more details, see MySQL DB Systems.
Before applying the kro definition, gather:
COMPARTMENT_OCID: OCI compartment for the MySQL DB SystemSUBNET_OCID: private subnet OCID for the MySQL DB SystemAVAILABILITY_DOMAIN: OCI availability domain for the DB SystemCONFIGURATION_OCID: MySQL configuration OCIDMYSQL_SHAPE_NAME: MySQL DB System shape supported in your tenancy
The checked-in OSOK MySQL sample uses MySQL.2 as an example shape, but you
should replace that with a shape supported in your tenancy.
Save the following file as osok-mysql-rgd.yaml and apply it once as a
cluster-level platform definition:
apiVersion: kro.run/v1alpha1
kind: ResourceGraphDefinition
metadata:
name: osok-mysql-system
spec:
schema:
apiVersion: v1alpha1
kind: OsokMysqlSystem
spec:
compartmentId: string | required=true
subnetId: string | required=true
availabilityDomain: string | required=true
configurationId: string | required=true
mysqlShapeName: string | required=true
mysqlAdminUsername: string | default="dbadmin"
mysqlAdminPassword: string | required=true
mysqlStorageSizeInGBs: integer | default=50
status:
dbSystemName: ${mysqlDbSystem.metadata.name}
dbSystemOCID: ${mysqlDbSystem.status.?status.?ocid.orValue("")}
connectionSecretName: ${mysqlDbSystem.metadata.name}
resources:
- id: mysqlAdminSecret
template:
apiVersion: v1
kind: Secret
metadata:
name: ${schema.metadata.name + "-mysql-admin"}
namespace: ${schema.metadata.namespace}
type: Opaque
stringData:
username: ${schema.spec.mysqlAdminUsername}
password: ${schema.spec.mysqlAdminPassword}
- id: mysqlDbSystem
readyWhen:
- ${mysqlDbSystem.status.?lifecycleState.orValue("") == "ACTIVE"}
template:
apiVersion: mysql.oracle.com/v1beta1
kind: DbSystem
metadata:
name: ${schema.metadata.name}
namespace: ${schema.metadata.namespace}
spec:
compartmentId: ${schema.spec.compartmentId}
displayName: ${schema.metadata.name}
shapeName: ${schema.spec.mysqlShapeName}
subnetId: ${schema.spec.subnetId}
configurationId: ${schema.spec.configurationId}
availabilityDomain: ${schema.spec.availabilityDomain}
adminUsername:
secret:
secretName: ${mysqlAdminSecret.metadata.name}
adminPassword:
secret:
secretName: ${mysqlAdminSecret.metadata.name}
dataStorageSizeInGBs: ${schema.spec.mysqlStorageSizeInGBs}
port: 3306
portX: 33060Apply it:
kubectl apply -f osok-mysql-rgd.yaml
kubectl get rgd osok-mysql-systemWhen the ResourceGraphDefinition becomes active, kro has created a new
OsokMysqlSystem API in the cluster.
Save the following as osok-mysql-system.yaml:
apiVersion: kro.run/v1alpha1
kind: OsokMysqlSystem
metadata:
name: mysql-demo
namespace: demo
spec:
compartmentId: ocid1.compartment.oc1..exampleuniqueID
subnetId: ocid1.subnet.oc1..exampleuniqueID
availabilityDomain: <AVAILABILITY_DOMAIN>
configurationId: ocid1.mysqlconfiguration.oc1..exampleuniqueID
mysqlShapeName: MySQL.2
mysqlAdminUsername: dbadmin
mysqlAdminPassword: change-me-for-test-only
mysqlStorageSizeInGBs: 50Create the namespace, then apply the single instance manifest:
kubectl create namespace demo
kubectl apply -f osok-mysql-system.yamlFor this quick start, the MySQL admin password is supplied on the custom resource for simplicity. For a production-grade design, move the credentials to a pre-created Secret and model that Secret as an external dependency instead of storing the password in the instance spec.
MySQL provisioning takes the longest. Watch the stack with:
kubectl get OsokMysqlSystem -n demo
kubectl get dbsystems.mysql.oracle.com -n demo
kubectl get secrets -n demoInspect the DbSystem resource:
kubectl describe dbsystem mysql-demo -n demoOSOK creates a same-name Secret after the DbSystem becomes active. Inspect
that connection Secret with:
kubectl get secret mysql-demo -n demo
kubectl get secret mysql-demo -n demo -o jsonpath='{.data.PrivateIPAddress}' | base64 --decode && echoAt the end of this flow you should have:
- one
OsokMysqlSystemresource managed by kro - one
DbSystemresource reconciled by OSOK - one OCI MySQL DB System in the target compartment
- one same-name Kubernetes Secret created by OSOK with the connection details
That Secret is the handoff point for workloads that need to connect to the MySQL DB System later.
Delete the instance first so kro and OSOK can tear down the managed resources:
kubectl delete OsokMysqlSystem mysql-demo -n demoIf you also want to remove the generated API:
kubectl delete rgd osok-mysql-systemIf you installed kro only for this example:
helm uninstall kro -n kro-systemAfter this quick start, continue with:
- Installation for the broader auth and bundle deployment paths
- Supported Resources for the generated package and kind catalog
- API Reference for generated field tables and sample links
- MySQL DB Systems for the service-specific MySQL guide