部署自管式 Oracle 数据库

本指南简要介绍了如何在 Google Distributed Cloud (GDC) 气隙式标准集群上部署自行管理的 Oracle Database Enterprise 实例。借助此部署,您可以在气隙式环境中运行 Oracle 工作负载,并利用 GDC 的现有存储和网络功能。

它使用官方的 Oracle Database Operator for Kubernetes,该运算符可 自动执行数据库的生命周期管理。

架构

该架构描述了由 Oracle Database Operator 在 GDC 标准集群中管理的单实例 Oracle 数据库部署。虽然本指南演示了如何部署单个数据库实例,但您可以根据集群的容量(RAM、CPU、磁盘空间)部署任意数量的实例。

单实例 Oracle 数据库部署架构图。

该架构包含以下关键组件:

  • GDC 项目:用于存放资源的 项目的容器。
  • 标准 Kubernetes 集群:提供计算资源的 标准集群
  • Oracle Database Operator:一个 Kubernetes 运算符,可自动执行 Oracle 数据库的 预配、生命周期管理和可观测性。 它可以简化补丁程序、备份和恢复等复杂任务,从而更轻松地在容器化环境中运行有状态 Oracle 工作负载。
  • 数据库实例:容器化的 Oracle 单实例数据库 (SIDB),具有永久性存储空间。
  • Harbor:用于在气隙式环境中托管数据库、 运算符和客户端映像的私有容器注册表。
  • Cert-manager:运算符依赖于 cert-manager 来管理 Webhook 证书。cert-manager 预安装在 GDC 标准集群上。

在本指南中,您将在自己的命名空间 (oracle-database-operator-system) 中部署运算符,并在单独的命名空间 (oracle-db) 中部署数据库实例。这些命名空间在架构图中使用虚线边框框出。

建议您进行这种分离,以提高清晰度和可管理性。不过,您可以自行决定如何组织数据库。例如,您可以根据工作负载需求、团队所有权或安全规范,将某些数据库分组到不同的命名空间中,以管理精细的访问权限控制 (RBAC)。

准备工作

在开始部署之前,您必须确保您的环境满足以下要求:

  • 创建一个项目 ,该项目将作为本 指南中生成的所有资源的持有者。
  • 为您的项目授予 Cluster Admin 和 Standard Cluster Admin 角色。这样,您就可以创建标准 Kubernetes 集群并管理其资源:

    export PROJECT_ID=PROJECT_ID
    export USER_NAME=USER_NAME
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=cluster-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=standard-cluster-admin
    
  • 创建一个 Harbor 实例 和一个 Harbor 项目 ,以托管本指南所需的容器映像。

  • 为您的用户授予 Harbor Instance Admin 角色,以便您可以将映像上传到 Harbor 实例:

    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=harbor-instance-admin
    
  • 在 Harbor 项目中创建一个 Harbor 机器人 账号 。在本指南的后续部分中,机器人账号的凭据将存储在 Kubernetes Secret 中,以便集群在实例化容器时从 Harbor 中拉取映像。

  • 创建一个包含两个工作器节点的标准 Kubernetes 集群,每个工作器节点至少具有 16 GB 的内存。例如:

    kubectl --kubeconfig MGMT_API_KUBECONFIG create -f - <<EOF
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: ${CLUSTER_NAME}
      namespace: ${PROJECT_ID}
    spec:
      nodePools:
      - machineTypeName: n3-standard-8-gdc
        nodeCount: 2
        name: ${CLUSTER_NAME}-node-pool
    EOF
    
  • 设置环境变量。在本指南中,这些变量将用于创建和引用资源:

    # General info
    export PROJECT_ID="PROJECT_ID"
    export ZONE="ZONE"
    export ORG_NAME="ORG_NAME"
    export CLUSTER_NAME="CLUSTER_NAME"
    
    # Oracle operator settings
    export ORACLE_OPERATOR_VERSION="2.1.0"
    export ORACLE_DB_VERSION="23.26.1.0"
    export ORACLE_OPERATOR_NAMESPACE="ORACLE_DBS_OPERATOR-SYSTEM"
    
    # Harbor config
    export HARBOR_INSTANCE_PROJECT_ID="HARBOR_PROJECT_ID"
    export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL"
    export HARBOR_PROJECT="HARBOR_PROJECT"
    export HARBOR_PULL_SECRET_NAME="HARBOR_PULL_SECRET_NAME"
    export HARBOR_ROBOT_ACCOUNT="robot\$HARBOR_PROJECT+ROBOT_NAME"
    export HARBOR_ROBOT_SECRET="HARBOR_ROBOT_SECRET"
    
    # Oracle database config
    export ADMIN_PASSWORD="ADMIN_PASSWORD"
    export DB_NAMESPACE="DB_NAMESPACE"
    export DB_NAME="DB_NAME"
    

    网络说明 :本指南假定它是在可以访问 GDC API 且可以访问互联网以下载 Oracle 运算符的清单和容器映像的堡垒节点上运行的。如果您是在无法访问互联网的机器上运行此指南,则必须单独获取这些资产(例如,使用 docker save 从已连接的机器导出映像,并使用 docker load 导入映像),并在继续操作之前安全地将其上传到您的环境。

  • container-registry.oracle.com上创建一个账号并获取 API 令牌,然后接受 Oracle Database Enterprise EditionOracle Instant Client 映像的许可协议,然后再 继续。

将映像加载到 Harbor

由于 Google Distributed Cloud 网闸隔离配置中的集群无法访问外部注册表,因此您必须将所需的映像镜像到您的私有 Harbor 实例。

登录 Oracle Container Registry

您必须先通过官方 Oracle 注册表进行身份验证,才能拉取基础映像:

docker --config=./docker-oracle login container-registry.oracle.com

成功登录后,凭据将保存在 ./docker-oracle/config.json 中。

将映像加载到 Harbor

通过您的私有 Harbor 实例进行身份验证:

docker --config=./docker-harbor login ${HARBOR_INSTANCE_URL} \
  -u ${HARBOR_ROBOT_ACCOUNT} \
  -p ${HARBOR_ROBOT_SECRET}

成功登录后,机器人账号的凭据将保存在 ./docker-harbor/config.json 中。

拉取、标记和推送映像

从官方 Oracle Container Registry 下载映像,并将其推送到您的内部 Harbor 项目。您将镜像运算符、企业数据库和即时客户端以进行测试。

  1. 镜像 Oracle Database Operator 映像:

    docker --config=./docker-oracle pull \
      container-registry.oracle.com/database/operator:${ORACLE_OPERATOR_VERSION} \
      --platform linux/amd64
    docker tag container-registry.oracle.com/database/operator:${ORACLE_OPERATOR_VERSION} \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-operator:${ORACLE_OPERATOR_VERSION}
    docker --config=./docker-harbor push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-operator:${ORACLE_OPERATOR_VERSION}
    
  2. 镜像 Oracle database Enterprise 映像:

    docker --config=./docker-oracle pull \
      container-registry.oracle.com/database/enterprise:${ORACLE_DB_VERSION} \
      --platform linux/amd64
    docker tag container-registry.oracle.com/database/enterprise:${ORACLE_DB_VERSION} \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-enterprise:${ORACLE_DB_VERSION}
    docker --config=./docker-harbor push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-enterprise:${ORACLE_DB_VERSION}
    
  3. 镜像 Oracle Instant Client 映像:

    docker --config=./docker-oracle pull container-registry.oracle.com/database/instantclient:latest \
      --platform linux/amd64
    docker tag container-registry.oracle.com/database/instantclient:latest \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-instantclient:latest
    docker --config=./docker-harbor push ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-instantclient:latest
    

配置集群访问权限

在部署资源之前,请检索标准集群的凭据并创建一个方便的别名:

  1. 检索标准集群的 kubeconfig:

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \
      get-credentials ${CLUSTER_NAME} \
      --standard \
      --project ${PROJECT_ID} \
      --zone ${ZONE}
    
  2. 创建 kk 别名以简化后续命令:

    alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"
    

创建 Secret

创建一个 Kubernetes Secret,以允许集群使用保存在本地 ./docker-harbor/config.json 中的凭据从 Harbor 中拉取映像。您需要在运算符的命名空间(用于拉取运算符映像)和数据库的命名空间(用于拉取数据库映像)中都使用此 Secret。

  1. 为运算符创建命名空间:

    kk create ns ${ORACLE_OPERATOR_NAMESPACE}
    
  2. 为运算符创建拉取 Secret:

    kk create secret docker-registry ${HARBOR_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker-harbor/config.json \
      -n ${ORACLE_OPERATOR_NAMESPACE}
    
  3. 为数据库创建命名空间:

    kk create ns ${DB_NAMESPACE}
    
  4. 为数据库创建拉取 Secret:

    kk create secret docker-registry ${HARBOR_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker-harbor/config.json \
      -n ${DB_NAMESPACE}
    

安装 Oracle Database Operator

现在,您可以通过应用三个清单将 Oracle Database Operator 安装到集群中:

  1. 集群角色绑定:为运算符设置必要的权限,使其能够在集群范围内运行。

    kk apply -f https://raw.githubusercontent.com/oracle/oracle-database-operator/refs/tags/v${ORACLE_OPERATOR_VERSION}/rbac/cluster-role-binding.yaml
    
  2. 节点 RBAC:授予读取节点拓扑的权限,这对于正确调度 pod 至关重要。

    kk apply -f https://raw.githubusercontent.com/oracle/oracle-database-operator/refs/tags/v${ORACLE_OPERATOR_VERSION}/rbac/node-rbac.yaml
    
  3. 运算符部署:部署运算符 pod 和自定义资源定义 (CRD)。此命令会下载官方清单,将映像路径替换为您的 Harbor 网址,注入 imagePullSecrets 配置,以便 Kubernetes 可以通过 Harbor 进行身份验证,并应用结果:

    curl -L https://raw.githubusercontent.com/oracle/oracle-database-operator/refs/tags/v${ORACLE_OPERATOR_VERSION}/oracle-database-operator.yaml \
      | sed "s|container-registry.oracle.com/database/operator:latest|${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-operator:${ORACLE_OPERATOR_VERSION}|g" \
      | awk "/terminationGracePeriodSeconds: 10/{print; print \"      imagePullSecrets:\n      - name: ${HARBOR_PULL_SECRET_NAME}\"; next}1" \
      | kk apply -f -
    

    等待运算符 pod 运行:

    kk get pods -n ${ORACLE_OPERATOR_NAMESPACE} --watch
    

    输出应如下所示:

    NAME                                                           READY   STATUS    RESTARTS   AGE
    oracle-database-operator-controller-manager-5f7b56874d-k9v4z   1/1     Running   0          45s
    oracle-database-operator-controller-manager-5f7b56874d-n2x8m   1/1     Running   0          45s
    oracle-database-operator-controller-manager-5f7b56874d-r6z7q   1/1     Running   0          45s
    

部署新的数据库实例

在运算符运行后,您现在可以部署单实例 Oracle 数据库。本指南将创建一个适用于开发或测试的基本 Enterprise Edition 实例。

  1. 创建一个 Kubernetes Secret 来存储数据库管理密码:

    kk create secret generic oracle-db-password \
      --from-literal=password=${ADMIN_PASSWORD} \
      -n ${DB_NAMESPACE}
    
  2. 应用 SingleInstanceDatabase 清单来创建数据库:

    apiVersion: database.oracle.com/v4
    kind: SingleInstanceDatabase
    metadata:
      name: ${DB_NAME}
      namespace: ${DB_NAMESPACE}
    spec:
      sid: ORCLCDB
      pdbName: ORCLPDB1
      edition: enterprise
      replicas: 1
      image:
        pullFrom: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-enterprise:${ORACLE_DB_VERSION}
        pullSecrets: ${HARBOR_PULL_SECRET_NAME}
        prebuiltDB: true
      persistence:
        size: 50Gi
        storageClass: standard-rwo
        accessMode: ReadWriteOnce
      adminPassword:
        secretName: oracle-db-password
        secretKey: password
    

    主要配置参数:

    • sid / pdbName :定义系统标识符 (SID) 和可插拔数据库 (PDB) 名称。
    • edition:指定数据库版本(在本例中为 enterprise)。
    • image:指向您的私有 Harbor 注册表映像。
    • persistence:使用 standard-rwo StorageClass 请求 50Gi 永久性卷,这会在 GDC 中创建一个可用区级永久性磁盘。
    • replicas:将 pod 的数量设置为 1。虽然 1 对于单实例来说很典型,但您可以针对特定用例(例如滚动更新,即在旧 pod 终止之前创建新 pod)或在使用支持并发访问的共享存储后端时增加此值。对于基本单实例部署,1 是标准值。

    如需查看配置选项的完整列表(包括自定义 init 参数 和资源限制),请参阅官方 文档

    数据库创建过程需要大量资源,可能需要 10 到 20 分钟。

  3. 等待数据库 pod 处于 Running 状态:

    kk get po -n ${DB_NAMESPACE} -l app=${DB_NAME} -w
    

    输出应如下所示:

    NAME                   READY   STATUS    RESTARTS   AGE
    my-db-i5xdj   0/1     Pending   0          0s
    my-db-i5xdj   0/1     Pending   0          0s
    my-db-i5xdj   0/1     Pending   0          1s
    my-db-i5xdj   0/1     Init:0/1   0          1s
    my-db-i5xdj   0/1     PodInitializing   0          98s
    my-db-i5xdj   0/1     Running           0          99s
    my-db-i5xdj   1/1     Running           0          99s
    
  4. 然后查看日志,等待 DATABASE IS READY TO USE! 消息:

    kk logs -n ${DB_NAMESPACE} -l app=${DB_NAME} -f
    

    输出应包含以下内容:

    #########################
    DATABASE IS READY TO USE!
    #########################
    
  5. 验证状态是否为 Healthy

    kk get singleinstancedatabase -n ${DB_NAMESPACE}
    

    输出应如下所示:

    NAME    EDITION      STATUS    ROLE
    my-db   Enterprise   Healthy   PRIMARY
    

访问和公开数据库

默认情况下,运算符会为数据库创建两个服务:

  1. ${DB_NAME} (ClusterIP) :用于集群内的内部流量。对于在同一集群内运行的应用,请使用此稳定的 DNS 名称。
  2. ${DB_NAME}-ext (NodePort) :用于外部访问。默认情况下,这会在每个节点上的高端口公开数据库。您可以通过在 SingleInstanceDatabase 规范中设置 loadBalancer: true 将其升级为负载均衡器服务。

如需详细了解如何自定义这些服务(例如定义 特定的 NodePort),请参阅 GitHub 文档

根据您的需求,选择以下方法之一来访问数据库。如需详细了解 GDC 服务类型,请参阅公开服务

在集群内访问 (ClusterIP)

如需从在同一 Kubernetes 集群内运行的其他 pod 访问数据库,请使用 ClusterIP 服务。

  1. 如需安全地验证这一点,请直接从临时客户端 pod 进行连接。
  2. 检查命名空间中的可用服务。请注意名为 ${DB_NAME}(例如 my-db)的 ClusterIP 服务。此名称用作内部连接的主机名。
  3. 部署包含 SQL*Plus 客户端的临时 pod。您可以使用镜像到 Harbor 注册表的 instantclient 映像:

    kk run sqlplus-client -n ${DB_NAMESPACE} --rm -it --restart=Never \
      --image=${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/oracle-instantclient:latest \
      --image-pull-policy=Always \
      --overrides='{"spec": {"imagePullSecrets": [{"name": "'${HARBOR_PULL_SECRET_NAME}'"}]}}' \
      -- sqlplus sys/${ADMIN_PASSWORD}@${DB_NAME}:1521/ORCLPDB1 as sysdba
    

    您应该会看到 SQL 提示符,表明连接成功。

  4. 创建一个示例表以验证写入权限:

    CREATE TABLE employees (id NUMBER, name VARCHAR2(50));
    INSERT INTO employees VALUES (1, 'John Doe');
    COMMIT;
    SELECT * FROM employees;
    

    输出应如下所示:

            ID NAME
    ---------- --------------------------------------------------
            1 John Doe
    
  5. 退出会话:

    exit
    

在 VPC 内访问(内部负载均衡器)

如需将数据库公开给位于同一 GDC 项目或 VPC 内但在 Kubernetes 集群外的其他资源(例如虚拟机),请使用内部负载均衡器。这样可以确保流量在隔离的网络环境中保持私密。如需了解详情,请参阅 GDC 内部负载均衡器 文档

由于运算符不会自动支持向生成的服务添加注解,因此您必须创建单独的服务资源。请注意 networking.gke.io/load-balancer-type: internal 注解,这是预配内部负载均衡器所必需的。

  1. 创建内部负载均衡器服务:

    apiVersion: v1
    kind: Service
    metadata:
      name: ${DB_NAME}-internal
      namespace: ${DB_NAMESPACE}
      annotations:
        networking.gke.io/load-balancer-type: internal
    spec:
      type: LoadBalancer
      selector:
        app: ${DB_NAME}
      ports:
      - name: sqlnet
        port: 1521
        targetPort: 1521
    
  2. 检索内部 IP 地址:

    export DB_INT_IP=$(kk get svc ${DB_NAME}-internal -n ${DB_NAMESPACE} \
      -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "Database Internal IP: ${DB_INT_IP}"
    

从 VPC 外部访问(外部负载均衡器)

如需将数据库公开给完全位于 GDC 环境或 VPC 外部的客户端(例如,来自公司网络或外部客户端),您可以使用外部负载均衡器。这会分配一个可从隔离的 VPC 边界外部访问的 IP 地址。如需了解详情,请参阅 GDC 外部负载均衡器 文档

如需创建外部负载均衡器,请更新 SingleInstanceDatabase 规范以设置 loadBalancer: true。这会将现有 ${DB_NAME}-ext 服务类型从 NodePort 更改为 LoadBalancer

  1. 更新规范:

    kk patch sidb ${DB_NAME} -n ${DB_NAMESPACE} --type='merge' \
      -p '{"spec":{"loadBalancer":true}}'
    
  2. 检索外部 IP 地址:

    export DB_EXT_IP=$(kk get svc ${DB_NAME}-ext -n ${DB_NAMESPACE} \
      -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "Database External IP: ${DB_EXT_IP}"
    

后续步骤