首页 / 常见问题 / 平台升级后,组件共享单节点读写可用 PVC 的 SonarQube 实例 Pod 启动失败(Init),如何处理?

平台升级后,组件共享单节点读写可用 PVC 的 SonarQube 实例 Pod 启动失败(Init),如何处理?

背景信息

问题描述

在 v3.14 之前版本的平台上基于单个仅允许 单节点读写(RWO)可用 PVC 部署的 SonarQube 实例,在平台升级至当前版本后,SonarQube 实例的 Pod 启动失败(有 1 个 Pod 持续处于 Init 状态)。

问题原因

使用单个 可用 PVC 部署的 SonarQube 实例的 2 个 Pod 会共用 1 个 PVC。

若 PVC 是基于 访问模式单节点读写 的存储类创建的,且不支持延迟绑定。平台升级或其他原因(删除、新建)引发 SonarQube 实例的 Pod 重建时,一旦 2 个 Pod(postgresql 和 sonarqube)在重建过程中被调度至集群中的不同节点,就会导致 Pod 启动失败。

2 个 Pod 抢占 PVC 的顺序会使 Pod 处于不同的状态:

临时解决方案:配置亲和性使实例 Pod 调度至同一节点

通过为 Sonarqube 资源配置 亲和性 (affinity),重建 Pod sonarqube 并使其调度至 Pod postgresql 所在节点。

操作步骤

  1. 查看并记录 Pod postgresql 的标签(labels)。

    例如:

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        app: sonar-postgresql
  2. 更新 Sonarqube 资源,添加亲和性(affinity)配置。

    配置示例及说明如下:

    apiVersion: operator.devops.alauda.io/v1alpha1
    kind: Sonarqube
    metadata:
      annotations:
        overrideIntegratedName: sonar
      name: sonar
      namespace: default
    spec:  
      # 添加 affinity 配置
      helmValues:
        affinity:
          podAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                # postgresql Pod 标签的键
                - key: app
                  operator: In
                  values:
                  # postgresql Pod 标签对应的值
                  - sonar-postgresql
              topologyKey: kubernetes.io/hostname
              weight: 100

验证方法

更新 Sonarqube 资源后,会自动重启 Pod sonarqube。待 Pod 重启后,若 Pod postgresql、sonarqube 被调度至同一节点,则表明亲和性配置已生效。

说明:后续若 Pod postgresql 发生重启并被调度至其他节点,只需重启 Pod sonarqube,使其重新调度至 postgresql Pod 所在节点即可。

持久解决方案:为各组件配置独立的 PVC

通过将旧 PVC 中任一 Pod(sonarqube 或 postgresql)的数据迁移到一个新的 PVC,为 SonarQube 的每个组件配置独立的可用 PVC。

提示:本文将以迁移 PostgreSQL 的数据到新的 PVC 为例说明配置操作。

操作步骤

  1. 前往 Container Platform,在 SonarQube 实例所在的命名空间下,为 PostgreSQL 组件创建一个新的可用 PVC(持久卷声明)。

  2. 停用 Pod postgresql 和 sonarqube,避免迁移过程中,有新的数据写入。

    1. 切换至 平台管理 视图,卸载 SonarQube 实例所在集群上的 devops-tool-operator(位于 应用商店 > Operators > 已部署 Operators 页面)。

      说明

      • 卸载 devops-tool-operator 是为了避免 Operator 还原 sonarqube 的配置,无法停用组件。

      • 卸载期间,无法部署工具,但不影响其他组件的使用。

    2. 将 SonarQube 实例组件(SonarQube 和 PostgreSQL)的 Deployment 的 实例数(replicas) 更新为 0,停用 Pod postgresql 和 sonarqube。

  3. 在 SonarQube 实例所在命名空间下,创建一个 Pod(同时挂载新旧 PVC),用于将旧 PVC 上的数据拷贝至新的 PVC。

    Pod 的 YAML 文件示例及说明如下:

    注意:需将其中的变量(<> 中内容)替换为实际值。

    apiVersion: v1
    kind: Pod
    metadata:
      name: copy-postgresql-data # Pod 的名称,可自定义
      namespace: <SonarQube 实例所在的命名空间名称>
    spec:
      restartPolicy: Never 
      containers:
        - name: copy
          image: <实际的带有 bash 的镜像地址>  # 例如:registry.alauda.cn:60080/ops/ubuntu:23。可以在环境中查找 builder-go 的镜像(命令行:kubectl get clustertask -A -o yaml | grep builder-go)
          command: ["/bin/bash", "-c", "--"]
          args:
            # - "while true; do sleep 36000; done;"
            # 拷贝 postgresql 数据库数据至新的 PVC 中
            - |
              set -ex ;
              mv -f /new/postgresql-db/ /new/postgresql-db-$(date +%Y%m%d%H%M%S) || true ;
              time cp --archive /old/postgresql-db/ /new/ ;
              ls -artl /new/postgresql-db/ ;
              du -sh /new/postgresql-db/ ;
    
          volumeMounts:
            - name: old-pvc
              mountPath: /old
            - name: new-pvc
              mountPath: /new
    
          resources:
            requests:
              cpu: 500m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 256Mi
    
      volumes:
        - name: old-pvc
          persistentVolumeClaim:
            claimName: <旧 PVC 的名称> 
        - name: new-pvc
          persistentVolumeClaim:
            claimName: <新 PVC 的名称>

    提示:待 Pod 正常结束后,可以使用 kubectl logs <Pod 名称> 命令查看拷贝日志。

  4. 重建 SonarQube 实例,为 PostgreSQL 组件指定新的 PVC。

    1. 在 SonarQube 实例所在集群的任一控制节点上,执行如下命令行更新 Sonarqube 资源。

      # 请将 SonarQube 实例的名称替换为实际值。例如:kubectl get sonarqubes.operator.devops.alauda.io sonar -o yaml > sonar.yaml
      kubectl get sonarqubes.operator.devops.alauda.io <SonarQube 实例的名称> -o yaml > <SonarQube 实例的名称>.yaml

      资源配置示例及说明如下:

      说明:仅需要更新 databaseExistingClaim 的值为 新 PVC 的名称 即可。

      apiVersion: operator.devops.alauda.io/v1alpha1
      kind: Sonarqube
      metadata:
        annotations:
          overrideIntegratedName: sonar
        creationTimestamp: "2024-01-07T07:47:21Z"
        finalizers:
        - finalizers.operator.devops.alauda.io
        generation: 1
        name: sonar
        namespace: default
        resourceVersion: "192082"
        uid: 26b75d9f-903f-4578-8c04-d2e081f1a246
      spec:
        account:
          ssoEnabled: false
        externalURL: http://192.168.131.28:32101
        integratedIntoPlatform: true
        persistence:
          pvc:
            databaseExistingClaim: <新 PVC 的名称>
            webServiceExistingClaim: sonar-nfs-rwo # 旧 PVC 的名称,使用原有的实际值即可
          type: PVC
        plugins:
          useDefaultPluginsPackage: true
        resourceAssign:
          globalAssign:
            resources:
              limits:
                cpu: "4"
                memory: 8Gi
              requests:
                cpu: "4"
                memory: 8Gi
          type: GlobalAssign
        service:
          nodePort:
            port: 32101
          type: NodePort
    2. 执行如下命令,重建 SonarQube 实例。

      提示:命令执行时,会由于 devops-tool-operator 组件未就绪,导致该命令无法立即返回。请勿中断命令执行,并继续执行部署 devops-tool-operator 操作,待 Operator 部署成功并就绪后,该命令可正常返回。

      cat <SonarQube 实例的名称>.yaml | kubectl replace --force -f -
  5. 重新部署 devops-tool-operator

    说明:devops-tool-operator 部署成功后,会自动设置 SonarQube 实例组件的 Deployment 的实例数并启动 Deployment。

验证方法

待 SonarQube 实例组件(SonarQube 和 PostgreSQL)的 Deployment 都启动成功后,若可以正常登录 SonarQube 查看完整的历史数据,且重新执行流水线时,SonarQube 正常可用,则表明配置已生效。

(可选)后续操作

待验证无误后,可通过清理旧 PVC 上的 PostgreSQL 组件相关的数据,释放存储空间。