在 AKS 上部署高度可用的 PostgreSQL 数据库

在本文中,你将在 AKS 上部署高度可用的 PostgreSQL 数据库。

重要

AKS 文档和示例中都提到了开源软件。 AKS 服务级别协议、有限保修和 Azure 支持不涵盖你部署的软件。 将开源技术与 AKS 一起使用时,请查阅相应社区和项目维护者提供的支持选项来制定计划。

例如,Ray GitHub 存储库描述了多个在响应时间、用途和支持级别方面各不相同的平台。

Microsoft 将负责生成我们在 AKS 上部署的开源包。 该责任包括对生成、扫描、签名、验证和修补过程拥有完整的所有权,以及对容器映像中的二进制文件的控制。 如需了解详细信息,请参阅 AKS 漏洞管理AKS 支持范围

为启动应用用户创建机密

  1. 使用 kubectl create secret 命令为启动应用用户生成一个机密,通过交互式登录来验证 PostgreSQL 部署。

    PG_DATABASE_APPUSER_SECRET=$(echo -n | openssl rand -base64 16)
    
    kubectl create secret generic db-user-pass \
        --from-literal=username=app \
        --from-literal=password="${PG_DATABASE_APPUSER_SECRET}" \
        --namespace $PG_NAMESPACE \
        --context $AKS_PRIMARY_CLUSTER_NAME
    
  2. 使用 kubectl get 命令验证是否已成功创建机密。

    kubectl get secret db-user-pass --namespace $PG_NAMESPACE --context $AKS_PRIMARY_CLUSTER_NAME
    

设置用于 PostgreSQL 群集的环境变量

  • 部署 ConfigMap,使用以下 kubectl apply 命令为 PostgreSQL 群集设置环境变量:

    cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME -n $PG_NAMESPACE -f -
    apiVersion: v1
    kind: ConfigMap
    metadata:
        name: cnpg-controller-manager-config
    data:
        ENABLE_AZURE_PVC_UPDATES: 'true'
    EOF
    

安装 Prometheus PodMonitor

Prometheus 使用 CNPG GitHub 示例存储库中存储的一组默认记录规则为 CNPG 实例创建 PodMonitor。 在生产环境中,将根据需要修改这些规则。

  1. 使用 helm repo add 命令添加 Prometheus 社区 Helm 存储库。

    helm repo add prometheus-community \
        https://prometheus-community.github.io/helm-charts
    
  2. 升级 Prometheus 社区 Helm 存储库,并使用带有 helm upgrade 标志的 --install 命令在主群集上安装它。

    helm upgrade --install \
        --namespace $PG_NAMESPACE \
        -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/main/docs/src/samples/monitoring/kube-stack-config.yaml \
        prometheus-community \
        prometheus-community/kube-prometheus-stack \
        --kube-context=$AKS_PRIMARY_CLUSTER_NAME
    

创建联合凭据

在本部分,你将创建 PostgreSQL 备份的联合标识凭据,以允许 CNPG 使用 AKS 工作负载标识向存储帐户目标进行身份验证来进行备份。 CNPG 运算符会创建一个与 CNPG 群集部署清单中使用的群集同名的 Kubernetes 服务帐户。

  1. 使用 az aks show 命令获取群集 OIDC 颁发者 URL。

    export AKS_PRIMARY_CLUSTER_OIDC_ISSUER="$(az aks show \
        --name $AKS_PRIMARY_CLUSTER_NAME \
        --resource-group $RESOURCE_GROUP_NAME \
        --query "oidcIssuerProfile.issuerUrl" \
        --output tsv)"
    
  2. 使用 az identity federated-credential create 命令创建联合标识凭据。

    az identity federated-credential create \
        --name $AKS_PRIMARY_CLUSTER_FED_CREDENTIAL_NAME \
        --identity-name $AKS_UAMI_CLUSTER_IDENTITY_NAME \
        --resource-group $RESOURCE_GROUP_NAME \
        --issuer "${AKS_PRIMARY_CLUSTER_OIDC_ISSUER}" \
        --subject system:serviceaccount:"${PG_NAMESPACE}":"${PG_PRIMARY_CLUSTER_NAME}" \
        --audience api://AzureADTokenExchange
    

部署高度可用的 PostgreSQL 群集

在本部分,你将使用 CNPG 群集自定义资源定义 (CRD) 部署高度可用的 PostgreSQL 群集。

群集 CRD 参数

下表概述了在群集 CRD 的 YAML 部署清单中设置的关键属性:

properties 定义
inheritedMetadata 特定于 CNPG 运算符。 元数据由与群集相关的所有对象继承。
annotations: service.beta.kubernetes.io/azure-dns-label-name 公开读写和只读 Postgres 群集终结点时要使用的 DNS 标签。
labels: azure.workload.identity/use: "true" 指示 AKS 应将工作负载标识依赖项注入托管 PostgreSQL 群集实例的 Pod。
topologySpreadConstraints 需要不同的区域和具有 "workload=postgres" 标签的不同节点。
resources 配置服务质量 (QoS) 类 Guaranteed。 在生产环境中,这些值是最大限度使用基础节点 VM 的关键,根据所使用的 Azure VM SKU 而有所不同。
bootstrap 特定于 CNPG 运算符。 使用空的应用数据库进行初始化。
storage / walStorage 特定于 CNPG 运算符。 为数据和日志存储的 PersistentVolumeClaim (PVC) 定义存储模板。 还可以为表空间指定存储来进行分片,以增加 IOPs。
replicationSlots 特定于 CNPG 运算符。 启用复制槽来实现高可用性。
postgresql 特定于 CNPG 运算符。 映射 postgresql.confpg_hba.confpg_ident.conf config 的设置。
serviceAccountTemplate 包含生成服务帐户所需的模板,并将 AKS 联合标识凭据映射到 UAMI,从而能够从托管 PostgreSQL 实例的 Pod 进行 AKS 工作负载标识身份验证来访问外部 Azure 资源。
barmanObjectStore 特定于 CNPG 运算符。 使用 AKS 工作负载标识配置 barman-cloud 工具套件,以便向 Azure Blob 存储对象存储进行身份验证。

PostgreSQL 性能参数

PostgreSQL 性能在很大程度上取决于群集的基础资源。 下表提供了有关如何计算高性能的关键参数的一些建议:

properties 建议的值 定义
wal_compression lz4 使用指定方法压缩 WAL 文件中的整页写入
max_wal_size 6GB 设置触发检查点的 WAL 大小
checkpoint_timeout 15 分钟 在自动 WAL 检查点之间设置最长时间
checkpoint_flush_after 2MB(兆字节) 在将以前执行的写入刷新到磁盘之前所要达到的页数
wal_writer_flush_after 2MB(兆字节) WAL 写入器写出的 WAL 数量,达到该数量将触发刷新
min_wal_size 4GB 设置要将 WAL 收缩到的最小大小
shared_buffers 25% 的节点内存 设置服务器使用的共享内存缓冲区数
effective_cache_size 75% 的节点内存 设置规划器关于数据缓存总大小的假设
work_mem 1/256 的节点内存 设置要用于查询工作区的最大内存
maintenance_work_mem 6.25% 的节点内存 设置用于维护操作的最大内存
autovacuum_vacuum_cost_limit 2400 autovacuum 在短暂睡眠之前可用的清空成本量
random_page_cost 1.1 设置规划器对不按顺序提取磁盘页的成本估计值
effective_io_concurrency 64 磁盘子系统可有效处理的同时请求数
maintenance_io_concurrency 64 用于维护工作的“effective_io_concurrency”变体

部署 PostgreSQL

  1. 使用 kubectl apply 命令通过群集 CRD 部署 PostgreSQL 群集。

    cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME -n $PG_NAMESPACE -v 9 -f -
    apiVersion: postgresql.cnpg.io/v1
    kind: Cluster
    metadata:
      name: $PG_PRIMARY_CLUSTER_NAME
    spec:
      inheritedMetadata:
        annotations:
          service.beta.kubernetes.io/azure-dns-label-name: $AKS_PRIMARY_CLUSTER_PG_DNSPREFIX
        labels:
          azure.workload.identity/use: "true"
    
      instances: 3
      startDelay: 30
      stopDelay: 30
      minSyncReplicas: 1
      maxSyncReplicas: 1
      replicationSlots:
        highAvailability:
          enabled: true
        updateInterval: 30
    
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            cnpg.io/cluster: $PG_PRIMARY_CLUSTER_NAME
    
      affinity:
        nodeSelector:
          workload: postgres
    
      resources:
        requests:
          memory: '8Gi'
          cpu: 2
        limits:
          memory: '8Gi'
          cpu: 2
    
      bootstrap:
        initdb:
          database: appdb
          owner: app
          secret:
            name: db-user-pass
          dataChecksums: true
    
      storage:
        size: 32Gi
        pvcTemplate:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 32Gi
          storageClassName: $POSTGRES_STORAGE_CLASS
    
      walStorage:
        size: 32Gi
        pvcTemplate:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 32Gi
          storageClassName: $POSTGRES_STORAGE_CLASS
    
      monitoring:
        enablePodMonitor: true
    
      postgresql:
        parameters:
          wal_compression: lz4
          max_wal_size: 6GB
          checkpoint_timeout: 15min
          checkpoint_flush_after: 2MB
          wal_writer_flush_after: 2MB
          min_wal_size: 4GB
          shared_buffers: 4GB
          effective_cache_size: 12GB
          work_mem: 62MB
          maintenance_work_mem: 1GB
          autovacuum_vacuum_cost_limit: "2400"
          random_page_cost: "1.1"
          effective_io_concurrency: "64"
          maintenance_io_concurrency: "64"
        pg_hba:
          - host all all all scram-sha-256
    
      serviceAccountTemplate:
        metadata:
          annotations:
            azure.workload.identity/client-id: "$AKS_UAMI_WORKLOAD_CLIENTID"
          labels:
            azure.workload.identity/use: "true"
    
      backup:
        barmanObjectStore:
          destinationPath: "https://${PG_PRIMARY_STORAGE_ACCOUNT_NAME}.blob.core.chinacloudapi.cn/backups"
          azureCredentials:
            inheritFromAzureAD: true
        retentionPolicy: '7d'
    EOF
    
  2. 使用 kubectl get 命令验证是否已成功创建主要 PostgreSQL 群集。 CNPG 群集 CRD 指定了三个实例,可以在启动并加入每个实例进行复制后查看正在运行的 Pod 来验证。 请耐心等待,因为所有三个实例需要一些时间才能联机并加入群集。

    kubectl get pods --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -l cnpg.io/cluster=$PG_PRIMARY_CLUSTER_NAME
    

    示例输出

    NAME                         READY   STATUS    RESTARTS   AGE
    pg-primary-cnpg-r8c7unrw-1   1/1     Running   0          4m25s
    pg-primary-cnpg-r8c7unrw-2   1/1     Running   0          3m33s
    pg-primary-cnpg-r8c7unrw-3   1/1     Running   0          2m49s
    

验证 Prometheus PodMonitor 是否正在运行

CNPG 运算符使用在 Prometheus 社区安装期间创建的记录规则自动为主实例创建 PodMonitor。

  1. 使用 kubectl get 命令验证 PodMonitor 是否正在运行。

    kubectl --namespace $PG_NAMESPACE \
        --context $AKS_PRIMARY_CLUSTER_NAME \
        get podmonitors.monitoring.coreos.com \
        $PG_PRIMARY_CLUSTER_NAME \
        --output yaml
    

    示例输出

     kind: PodMonitor
     metadata:
      annotations:
        cnpg.io/operatorVersion: 1.23.1
    ...
    

如果使用适用于托管 Prometheus 的 Azure Monitor,需要使用自定义组名再添加一个 Pod 监视器。 托管 Prometheus 不会从 Prometheus 社区获取自定义资源定义 (CRD)。 除了组名外,CRD 是相同的。 这使得托管 Prometheus 的 Pod 监视器能够与使用社区 Pod 监视器的项并排存在。 如果没有使用托管 Prometheus,可跳过此操作。 创建新的 Pod 监视器:

cat <<EOF | kubectl apply --context $AKS_PRIMARY_CLUSTER_NAME --namespace $PG_NAMESPACE -f -
apiVersion: azmonitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: cnpg-cluster-metrics-managed-prometheus
  namespace: ${PG_NAMESPACE}
  labels:
    azure.workload.identity/use: "true"
    cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
spec:
  selector:
    matchLabels:
      azure.workload.identity/use: "true"
      cnpg.io/cluster: ${PG_PRIMARY_CLUSTER_NAME}
  podMetricsEndpoints:
    - port: metrics
EOF

验证是否已创建 Pod 监视器(请注意组名的差异)。

kubectl --namespace $PG_NAMESPACE \
    --context $AKS_PRIMARY_CLUSTER_NAME \
    get podmonitors.azmonitoring.coreos.com \
    -l cnpg.io/cluster=$PG_PRIMARY_CLUSTER_NAME \
    -o yaml

选项 A - Azure Monitor 工作区

部署 Postgres 群集和 Pod 监视器后,可以在 Azure Monitor 工作区中使用 Azure 门户查看指标。

显示 Azure Monitor 工作区中的指标的屏幕截图。

选项 B - 托管 Grafana

或者,部署 Postgres 群集和 Pod 监视器后,可以在部署脚本创建的托管 Grafana 实例上创建指标仪表板,可视化导出到 Azure Monitor 工作区的指标。 可以通过 Azure 门户访问托管 Grafana。 导航到部署脚本创建的托管 Grafana 实例,然后单击“终结点”链接,如下所示:

显示 Azure 托管 Grafana 实例的屏幕截图。

单击“终结点”链接会打开新的浏览器窗口,可在这里创建关于托管 Grafana 实例的仪表板。 按照说明配置 Azure Monitor 数据源,然后就可添加可视化效果,创建 Postgres 群集指标仪表板。 设置数据源连接后,在主菜单中单击“数据源”选项,你应该会看到一组用于数据源连接的数据源选项,如下所示:

显示数据源选项的屏幕截图。

在“托管 Prometheus”选项上,单击生成仪表板的选项以打开仪表板编辑器。 编辑器窗口打开后,单击“添加可视化效果”选项,然后单击“托管 Prometheus”选项,浏览来自 Postgres 群集的指标。 选择要可视化的指标后,单击“运行查询”按钮来提取数据进行可视化,如下所示:

显示构造仪表板的屏幕截图。

单击“保存”按钮,将面板添加到仪表板。 可以单击仪表板编辑器中的“添加”按钮来添加其他面板,并重复此过程来可视化其他指标。 添加指标可视化效果后,应会显示如下所示的内容:

显示保存仪表板的屏幕截图。

单击“保存”图标以保存仪表板。


后续步骤

供稿人

Microsoft 会维护本文。 本系列文章为以下参与者的原创作品:

  • Ken Kilty | 首席 TPM
  • Russell de Pina | 首席 TPM
  • Adrian Joian | 高级客户工程师
  • Jenny Hayes | 高级内容开发人员
  • Carol Smith | 高级内容开发人员
  • Erin Schaffer | 内容开发人员 2
  • Adam Sharif | 客户工程师 2