转移数据

数据转移可以在以下对象之间进行:

  1. 永久性卷声明 (PVC) 和对象存储
  2. 对象存储和对象存储(在 GDC 中)

GDC 上的对象存储与 S3 兼容,在 Kubernetes YAML 中称为 s3 类型。

数据源和目标的类型

  1. 对象存储(称为“s3”):GDC 上存在的对象存储
  2. 本地存储空间(称为“本地”):附加 PVC 上的存储空间

从对象存储复制到对象存储

确保您满足以下前提条件:

  • 一个具有源读取权限的 S3 端点,以及一个具有目标写入权限的 S3 端点。
  • 如果您没有使用相应凭据创建存储桶的权限,则在目标存储桶不存在的情况下,转移作业会失败。如果目标存储桶存在,请确保这一点。
  • 在集群或命名空间内创建作业以及创建或读取 Secret 的权限。如需了解权限,请参阅以下示例。

设置数据传输

如需设置数据传输,请完成以下步骤:

创建转移命名空间

创建转移作业将运行的命名空间:

apiVersion: v1
kind: Namespace
metadata:
  name: NAMESPACE

配置凭据

准备好要转移的凭据。请选择与您的转移方案最相符的选项。

GDC 到 GDC 的转移

如果转移完全在同一 GDC 世界中进行,则密钥已存在。请注意,此方法仅适用于单个宇宙内的转移,不适用于不同宇宙之间的转移。

  1. 如需获取 S3 凭据密钥,请按照授予存储桶访问权限中的说明操作。

  2. 在目标命名空间中为转移作业创建服务账号 (SA)。然后,添加权限以允许此账号使用跨命名空间 RoleBinding 读取源命名空间和目标命名空间中的 Secret。

    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: transfer-service-account
      namespace: DESTINATION_NAMESPACE
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: read-secrets-role
      namespace: SOURCE_NAMESPACE
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-source-secrets-rolebinding
      namespace: SOURCE_NAMESPACE
    subjects:
    - kind: ServiceAccount
      name: transfer-service-account
      namespace: DESTINATION_NAMESPACE
    roleRef:
      kind: Role
      name: read-secrets-role
      apiGroup: rbac.authorization.k8s.io
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: read-secrets-role
      namespace: DESTINATION_NAMESPACE
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-dest-secrets-rolebinding
      namespace: DESTINATION_NAMESPACE
    subjects:
    - kind: ServiceAccount
      name: transfer-service-account
      namespace: DESTINATION_NAMESPACE
    roleRef:
      kind: Role
      name: read-secrets-role
      apiGroup: rbac.authorization.k8s.io
    ---
    

从 GDC 转移到非 GDC

对于涉及外部系统的转移,您必须明确指定访问凭据。

  1. 在目标命名空间中创建凭据:

    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: src-secret
      namespace: NAMESPACE
    data:
      access-key-id: NkFDTUg3WDBCVDlQMVpZMU5MWjU= # base 64 encoded version of key
      access-key: VkRkeWJsbFgzb2FZanMvOVpnSi83SU5YUjk3Y0Q2TUdxZ2d4Q3dpdw== # base 64 encoded version of secret key
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: dst-secret
      namespace: NAMESPACE
    data:
      access-key-id: NkFDTUg3WDBCVDlQMVpZMU5MWjU= # base 64 encoded version of key
      access-key: VkRkeWJsbFgzb2FZanMvOVpnSi83SU5YUjk3Y0Q2TUdxZ2d4Q3dpdw== # base 64 encoded version of secret key
    ---
    
  2. 创建供转移使用的服务账号 (SA),然后使用角色和角色绑定向该账号添加读取和写入 Secret 的权限。如果您的默认命名空间服务账号或自定义服务账号已拥有这些权限,则无需添加权限。

    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: transfer-service-account
      namespace: NAMESPACE
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: read-secrets-role
      namespace: NAMESPACE
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: read-secrets-rolebinding
      namespace: NAMESPACE
    subjects:
    - kind: ServiceAccount
      name: transfer-service-account
      namespace: NAMESPACE
    roleRef:
      kind: Role
      name: read-secrets-role
      apiGroup: rbac.authorization.k8s.io
    ---
    

获取 CA 证书

获取对象存储系统的 CA 证书。您可以按照获取信任包的说明,从 AO 或 PA 获取相同的证书。

---

apiVersion: v1
kind: Secret
metadata:
  name: src-cert
  namespace: NAMESPACE
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURBekNDQWV1Z0F3SUJBZ0lSQUpHM2psOFZhTU85a1FteGdXUFl3N3d3RFFZSktvWklodmNOQVFFTEJRQXcKR3pFWk1CY0dBMVVFQXhNUVltOXZkSE4wY21Gd0xYZGxZaTFqWVRBZUZ3MHlNekF5TVRVd01USXlNakZhRncweQpNekExTVRZd01USXlNakZhTUJzeEdUQVhCZ05WQkFNVEVHSnZiM1J6ZEhKaGNDMTNaV0l0WTJFd2dnRWlNQTBHCkNTcUdTSWI== # base 64 encoded version of certificate

---

apiVersion: v1
kind: Secret
metadata:
  name: dst-cert
  namespace: NAMESPACE
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURBekNDQWV1Z0F3SUJBZ0lSQUtoaEJXWWo3VGZlUUZWUWo0U0RpckV3RFFZSktvWklodmNOQVFFTEJRQXcKR3pFWk1CY0dBMVVFQXhNUVltOXZkSE4wY21Gd0xYZGxZaTFqWVRBZUZ3MHlNekF6TURZeU16TTROVEJhRncweQpNekEyTURReU16TTROVEJhTUJzeEdUQVhCZ05WQkFNVEVHSnZiM1J6ZEhKaGNDMTNaV0l0WTJFd2dnRWlNQTBHCkNTcUdTSWIzRFFF== # base 64 encoded version of certificate. Can be same OR different than source certificate.

---

(可选)创建 LoggingTarget

创建 LoggingTarget 以在 Loki 中查看转移服务日志。

apiVersion: logging.gdc.goog/v1
kind: LoggingTarget
metadata:
  namespace: NAMESPACE # Same namespace as your transfer job
  name: logtarg1
spec:
  # Choose matching pattern that identifies pods for this job
  # Optional
  # Relationship between different selectors: AND
  selector:

    # Choose pod name prefix(es) to consider for this job
    # Observability platform will scrape all pods
    # where names start with specified prefix(es)
    # Should contain [a-z0-9-] characters only
    # Relationship between different list elements: OR
    matchPodNames:
      - transfer-job # Choose the prefix here that matches your transfer job name
  serviceName: transfer-service

创建转移工作负载

您可以使用 Job 将转移作业作为一次性操作运行,也可以使用 CronJob 将其安排为重复运行。

选择最适合您使用场景的方法:

创建一次性作业

将此配置用于单个手动数据传输。

---
apiVersion: batch/v1
kind: Job
metadata:
  name: transfer-job
  namespace: NAMESPACE
spec:
  template:
    spec:
      serviceAccountName: transfer-service-account # The service account created in the previous step
      containers:
        - name: storage-transfer-pod
          image: gcr.io/private-cloud-staging/storage-transfer:latest
          imagePullPolicy: Always
          command:
            - /storage-transfer
          args:
            # The S3 endpoints for your source and destination
            - '--src_endpoint=SRC_ENDPOINT'
            - '--dst_endpoint=DST_ENDPOINT'
            # The Fully Qualified Names (FQN) of the buckets
            - '--src_path=SRC_BUCKET_FQN/'
            - '--dst_path=DST_BUCKET_FQN/'
            # Cross-namespace mapping: point directly to the live credentials using NAMESPACE/SECRET_NAME
            - '--src_credentials=NAMESPACE/SRC_SECRET_NAME'
            - '--dst_credentials=NAMESPACE/DST_SECRET_NAME'
            # Point to the CA certificate Secret created in the destination namespace
            - '--src_ca_certificate_reference=NAMESPACE/CA_CERT_SECRET'
            - '--dst_ca_certificate_reference=NAMESPACE/CA_CERT_SECRET'
            - '--src_type=s3'
            - '--dst_type=s3'
            - '--bandwidth_limit=BANDWIDTH_LIMIT' # Optional. Examples: '10K', '100M', '1G'
      restartPolicy: OnFailure
---

创建已调度的 CronJob

使用此配置可让目标存储桶按固定时间表与源存储桶保持持续同步。

---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: transfer-cronjob
  namespace: NAMESPACE
spec:
  schedule: "0 * * * *"  # Runs at the top of every hour. Adjust the cron schedule as needed.
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: transfer-service-account # The service account created in the previous step
          containers:
            - name: storage-transfer-pod
              image: gcr.io/private-cloud-staging/storage-transfer:latest
              imagePullPolicy: Always
              command:
                - /storage-transfer
              args:
                # The S3 endpoints for your source and destination
                - '--src_endpoint=SRC_ENDPOINT'
                - '--dst_endpoint=DST_ENDPOINT'
                # The Fully Qualified Names (FQN) of the buckets
                - '--src_path=SRC_BUCKET_FQN/'
                - '--dst_path=DST_BUCKET_FQN/'
                # Cross-namespace mapping: point directly to the live credentials using NAMESPACE/SECRET_NAME
                - '--src_credentials=NAMESPACE/SRC_SECRET_NAME'
                - '--dst_credentials=NAMESPACE/DST_SECRET_NAME'
                # Point to the CA certificate Secret created in the destination namespace
                - '--src_ca_certificate_reference=NAMESPACE/CA_CERT_SECRET'
                - '--dst_ca_certificate_reference=NAMESPACE/CA_CERT_SECRET'
                - '--src_type=s3'
                - '--dst_type=s3'
                - '--bandwidth_limit=BANDWIDTH_LIMIT' # Optional. Examples: '10K', '100M', '1G'
          restartPolicy: OnFailure
---

监控数据转移

实例化作业后,您可以使用 kubectl 命令(例如 kubectl describe)监控其状态。如需验证转移,请列出目标存储桶中的对象,以验证数据是否已转移。数据转移工具与转移所涉及的端点的位置无关。

运行以下命令以检查工作负载的状态:

# If you created a one-time Job:
kubectl describe job transfer-job -n NAMESPACE

# If you created a scheduled CronJob:
kubectl describe cronjob transfer-cronjob -n NAMESPACE

上述命令会告知您作业的状态。

作业会提示 pod 转移数据。您可以获取 pod 的名称,并查看日志,了解转移过程中是否存在任何错误。

如需查看 pod 日志,请运行以下命令:

# 1. First, find the exact pod name generated by your Job
kubectl get pods -n NAMESPACE | grep transfer

# 2. Then, view the logs for that specific pod
kubectl logs POD_NAME -n NAMESPACE

成功作业日志:

DEBUG : Starting main for transfer
I0607 21:34:39.183106       1 transfer.go:103]  "msg"="Starting transfer "  "destination"="sample-bucket" "source"="/data"
2023/06/07 21:34:39 NOTICE: Bandwidth limit set to {100Mi 100Mi}
I0607 21:34:49.238901       1 transfer.go:305]  "msg"="Job finished polling "  "Finished"=true "Number of Attempts"=2 "Success"=true
I0607 21:34:49.239675       1 transfer.go:153]  "msg"="Transfer completed."  "AvgSpeed"="10 KB/s" "Bytes Moved"="10.0 kB" "Errors"=0 "Files Moved"=10 "FilesComparedAtSourceAndDest"=3 "Time since beginning of transfer"="1.0s"

查看日志可让您了解数据传输速度(不同于所用带宽)、移动的字节数、出错的文件数和移动的文件数。

将块存储复制到对象存储

请确保您满足以下前提条件:

  • 一个 S3 端点,其中包含 S3 密钥 ID 和私有访问密钥,并且至少具有对您要将数据转移到的专用存储桶的写入权限。
  • 一个可正常运行且可连接到 S3 端点的集群。
  • 在集群内创建作业和 Secret 的权限。
  • 对于块存储复制,需要满足以下条件:Pod 附有要备份到对象存储的 PersistentVolumeClaim (PVC),并且拥有检查正在运行的作业和 PVC 的权限。
  • 对于块存储的复制,指在 PersistentVolume (PV) 上不进行任何写入操作的时间段。
  • 从对象存储端点恢复块存储的权限,即分配具有足够容量的 PV 的权限。

如需将 PV 复制到对象存储空间,您必须将卷附加到现有 Pod。在转移窗口期间,Pod 不得执行任何写入操作。为避免从作业中分离已挂载的 PV,数据传输过程通过在与 Pod 相同的机器上运行传输作业,并使用 hostPath 挂载来公开磁盘上的卷。在准备转移时,您必须先找到 Pod 正在运行的节点,以及其他元数据(例如 Pod UID 和 PVC 类型),以便引用节点上的相应路径。您必须将此元数据替换为下一部分中概述的示例 YAML 文件。

收集元数据

如需收集创建数据转移作业所需的元数据,请按以下步骤操作:

  1. 查找已安排 Pod 的节点:

    kubectl get pod POD_NAME -o jsonpath='{.spec.nodeName}'
    

    记录此命令的输出,作为数据传输作业 YAML 文件中使用的 NODE_NAME

  2. 查找 Pod UID:

    kubectl get pod POD_NAME -o 'jsonpath={.metadata.uid}'
    

    记录此命令的输出,作为数据传输作业 YAML 文件中使用的 POD_UID

  3. 查找 PVC 名称:

    kubectl get pvc www-web-0 -o 'jsonpath={.spec.volumeName}'
    

    记录此命令的输出,作为数据传输作业 YAML 文件中使用的 PVC_NAME

  4. 查找 PVC 存储空间配置程序:

    kubectl get pvc www-web-0 -o jsonpath='{.metadata.annotations.volume\.v1\.kubernetes\.io\/storage-provisioner}'
    

    记录此命令的输出,作为数据传输作业 YAML 文件中要使用的 PROVISIONER_TYPE

创建 Secret

如需跨集群将文件复制到对象存储空间,您必须先在 Kubernetes 集群中实例化 Secret。您必须为 Secret 数据使用匹配的密钥,以便该工具提取凭据。

如需在现有命名空间中执行转移,请参阅以下在 transfer 命名空间中创建 Secret 的示例:

apiVersion: v1
kind: Secret
metadata:
  name: src-secret
  namespace: transfer
data:
  access-key-id: c3JjLWtleQ== # echo -n src-key| base64 -w0
  access-key: c3JjLXNlY3JldA== # echo -n src-secret| base64 -w0
---
apiVersion: v1
kind: Secret
metadata:
  name: dst-secret
  namespace: transfer
data:
  access-key-id: ZHN0LWtleQ== # echo -n dst-key| base64 -w0
  access-key: ZHN0LXNlY3JldA== # echo -n dst-secret| base64 -w0

创建作业

使用您在上一部分中收集的数据,通过数据传输工具创建作业。数据传输作业具有 hostPath 装载,用于引用相关 PV 的路径,以及相关节点的 nodeSelector

以下是数据转移作业的示例:

apiVersion: batch/v1
kind: Job
metadata:
  name: transfer-job
  namespace: transfer
spec:
  template:
    spec:
      nodeSelector: NODE_NAME
      serviceAccountName: data-transfer-sa
      containers:
      - name: storage-transfer-pod
        image: storage-transfer
        command:
        - /storage-transfer
        args:
        - --dst_endpoint=https://your-dst-endpoint.com
        - --src_path=/pvc-data
        - --dst_path=transfer-dst-bucket
        - --dst_credentials=transfer/dst-secret
        - --src_type=local
        - --dst_type=s3
      volumeMounts:
      - mountPath: /pvc-data
        name: pvc-volume
      volumes:
      - name: pvc-volume
      hostPath:
        path: /var/lib/kubelet/pods/POD_UID/volumes/PROVISIONER_TYPE/PVC_NAME
      restartPolicy: Never

S3 数据转移一样,您必须在 Kubernetes 集群中创建一个包含目标端点访问密钥的 Secret,并且数据转移作业必须以具有足够权限的服务账号运行,才能从 API 服务器读取 Secret。使用对作业运行的标准 kubectl 命令监控转移的状态。

将块存储转移到对象存储时,请考虑以下详细信息:

  • 默认情况下,符号链接会遵循并复制到对象存储空间,但会执行深层复制,而不是浅层复制。恢复时,它会销毁符号链接。
  • 与对象存储复制一样,克隆到存储桶的子目录中会破坏现有数据。确保相应存储桶专供您的卷使用。

从对象存储恢复到块存储

分配 PV

如需从对象存储端点恢复块存储,请按以下步骤操作:

  1. 在恢复中为目标分配永久性卷。使用 PVC 分配卷,如以下示例所示:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: restore-pvc
      namespace: restore-ns
    spec:
      storageClassName: "default"
      accessModes:
    ReadWriteOnce
      resources:
        requests:
          storage: 1Gi # Need sufficient capacity for full restoration.
    
  2. 检查 PVC 的状态:

    kubectl get pvc restore-pvc -n restore-ns
    

    当 PVC 处于 Bound 状态时,即可在重新水合它的 Pod 中使用。

  3. 如果 StatefulSet 最终会使用 PV,您必须匹配渲染的 StatefulSet PVC。StatefulSet 生成的 Pod 会使用已完成水合的卷。以下示例展示了名为 ss 的 StatefulSet 中的卷声明模板。

      volumeClaimTemplates:
      - metadata:
          name: pvc-name
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "default"
          resources:
            requests:
              storage: 1Gi
    
  4. 预先分配名称为 ss-pvc-name-0ss-pvc-name-1 等的 PVC,以确保生成的 Pod 使用预先分配的卷。

为 PV 提供水分

将 PVC 绑定到 PV 后,启动作业以填充 PV:

apiVersion: batch/v1
kind: Job
metadata:
  name: transfer-job
  namespace: transfer
spec:
  template:
    spec:
      serviceAccountName: data-transfer-sa
      volumes:
      - name: data-transfer-restore-volume
        persistentVolumeClaim:
          claimName: restore-pvc
      containers:
      - name: storage-transfer-pod
        image: storage-transfer
        command:
        - /storage-transfer
        args:
        - --src_endpoint=https://your-src-endpoint.com
        - --src_path=/your-src-bucket
        - --src_credentials=transfer/src-secret
        - --dst_path=/restore-pv-mnt-path
        - --src_type=s3
        - --dst_type=local
      volumeMounts:
      - mountPath: /restore-pv-mnt-path
        name: data-transfer-restore-volume

作业运行完毕后,对象存储桶中的数据会填充卷。单独的 Pod 可以使用相同的标准卷装载机制来使用数据。