Transferir dados

As transferências de dados podem ocorrer entre:

  1. Declaração de volume permanente (PVC, na sigla em inglês) e armazenamento de objetos
  2. Armazenamento de objetos e armazenamento de objetos (no GDC)

O armazenamento de objetos no GDC é compatível com o S3 e é chamado de tipo s3 em yamls do Kubernetes.

Tipos de fontes e destinos de dados

  1. Armazenamento de objetos (chamado de "s3"): armazenamento de objetos presente no GDC
  2. Armazenamento local (chamado de "local"): armazenamento em PVCs anexados

Como copiar do armazenamento de objetos para o armazenamento de objetos

Verifique se você tem os seguintes pré-requisitos:

  • Um endpoint do S3 com permissões de leitura para a origem e um endpoint do S3 com permissões de gravação para o destino.
  • Se você não tiver permissão para criar buckets com as credenciais, a transferência vai falhar se o bucket de destino não existir. Verifique se o bucket de destino existe.
  • Privilégios para criar jobs e criar ou ler secrets no cluster ou namespace. Consulte o exemplo a seguir para permissões.

Configurar a transferência de dados

Para configurar a transferência de dados, siga estas etapas:

Criar o namespace de transferência

Crie o namespace em que o job de transferência será executado:

apiVersion: v1
kind: Namespace
metadata:
  name: NAMESPACE

Configurar credenciais

Prepare suas credenciais para a transferência. Siga a opção que melhor corresponde ao cenário de transferência.

Transferência do GDC para o GDC

Para uma transferência que ocorre completamente no mesmo universo do GDC, os secrets já existem. Esse método é estritamente para transferências em um único universo, não para transferências entre universos diferentes.

  1. Para receber os secrets de credenciais do S3, siga as instruções para conceder acesso ao bucket.

  2. Crie uma conta de serviço (SA) no namespace de destino para o job de transferência. Em seguida, adicione permissões para permitir que essa conta leia secrets nos namespaces de origem e destino usando RoleBindings entre namespaces.

    ---
    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
    ---
    

Transferência do GDC para não GDC

Para uma transferência que envolva um sistema externo, especifique as credenciais de acesso explicitamente.

  1. Crie credenciais no namespace de destino:

    ---
    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. Crie uma conta de serviço (SA) usada pela transferência e adicione permissões à conta para ler e gravar secrets usando papéis e vinculações de papéis. Não é necessário adicionar permissões se a SA do namespace padrão ou a SA personalizada já tiver essas permissões.

    ---
    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
    ---
    

Receber certificados de CA

Receba os certificados de CA para seus sistemas de armazenamento de objetos. Você pode receber os mesmos certificados do AO ou PA seguindo as instruções para buscar pacotes de confiança.

---

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.

---

(Opcional) Criar um LoggingTarget

Crie um LoggingTarget para conferir os registros do serviço de transferência no 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

Criar a carga de trabalho de transferência

Você pode executar a transferência como uma operação única usando um Job ou programá-la para ser executada repetidamente usando um CronJob.

Escolha o método que melhor se adapta ao seu caso de uso:

Criar um job único

Use essa configuração para uma transferência de dados manual e única.

---
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
---

Criar um CronJob programado

Use essa configuração para manter o bucket de destino sincronizado continuamente com o bucket de origem em uma programação fixa.

---
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
---

Monitorar a transferência de dados

Depois de instanciar o job, você pode monitorar o status dele usando kubectl comandos, como kubectl describe. Para verificar a transferência, liste os objetos no bucket de destino para validar se os dados foram transferidos. A ferramenta de transferência de dados é independente do local dos endpoints envolvidos na transferência.

Execute o seguinte comando para verificar o status da carga de trabalho:

# 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

O comando anterior informa o status do job.

O job solicita que um pod transfira os dados. Você pode acessar o nome do pod e conferir os registros para verificar se há erros durante a transferência.

Para conferir os registros do pod, execute o seguinte:

# 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

Registros de jobs concluídos:

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"

A visualização de registros permite conferir a velocidade de transferência de dados, que não é a mesma que a largura de banda usada, os bytes movidos, o número de arquivos com erros e os arquivos movidos.

Copiar armazenamento em blocos para armazenamento de objetos

Verifique se você atende aos seguintes pré-requisitos:

  • Um endpoint do S3 com um ID de chave do S3 e uma chave de acesso secreta com pelo menos permissões de GRAVAÇÃO para o bucket dedicado para o qual você quer transferir dados.
  • Um cluster em funcionamento com conectividade ao endpoint do S3.
  • Privilégios para criar jobs e secrets no cluster.
  • Para replicação do armazenamento em blocos, um pod com um PersistentVolumeClaim (PVC) anexado que você quer fazer backup para o armazenamento de objetos e privilégios para inspecionar jobs e PVCs em execução.
  • Para replicação do armazenamento em blocos, uma janela durante a qual nenhuma gravação ocorre no PersistentVolume (PV).
  • Para a restauração do armazenamento em blocos de um endpoint de repositório de objetos, privilégios para alocar um PV com capacidade suficiente.

Para replicar um PV para o armazenamento de objetos, é necessário anexar um volume a um pod existente. Durante a janela da transferência, o pod não pode executar nenhuma gravação. Para evitar desanexar o PV montado do job, o processo de transferência de dados funciona executando o job de transferência na mesma máquina que o pod e usando uma montagem hostPath para expor o volume no disco. Em preparação para a transferência, primeiro encontre o nó em que o pod está em execução e metadados adicionais, como o UID do pod e o tipo de PVC, para referenciar o caminho apropriado no nó. Você precisa substituir esses metadados no arquivo YAML de amostra descrito na seção a seguir.

Coletar metadados

Para coletar os metadados necessários para criar o job de transferência de dados, siga estas etapas:

  1. Encontre o nó que tem o pod programado:

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

    Grave a saída desse comando como NODE_NAME para usar no arquivo YAML do job de transferência de dados.

  2. Encontre o UID do pod:

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

    Grave a saída desse comando como o POD_UID para usar no arquivo YAML do job de transferência de dados.

  3. Encontre o nome do PVC:

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

    Grave a saída desse comando como PVC_NAME para usar no arquivo YAML do job de transferência de dados.

  4. Encontre o provisionador de armazenamento de PVC:

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

    Grave a saída desse comando como PROVISIONER_TYPE para usar no arquivo YAML do job de transferência de dados.

Criar Secrets

Para replicar o arquivo para o armazenamento de objetos em clusters, primeiro instancie os secrets no cluster do Kubernetes. Você precisa usar chaves correspondentes para os dados do secret para que a ferramenta extraia as credenciais.

Para realizar a transferência em um namespace atual, consulte o exemplo a seguir de criação de secrets em um namespace transfer:

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

Crie o job

Com os dados coletados na seção anterior, crie um job com a ferramenta de transferência de dados. O job de transferência de dados tem uma montagem hostPath que referencia o caminho para o PV de interesse e um nodeSelector para o nó relevante.

Confira a seguir um exemplo de job de transferência de dados:

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

Assim como na transferência de dados do S3, é necessário criar um secret que contenha as chaves de acesso para o endpoint de destino no cluster do Kubernetes, e o job de transferência de dados precisa ser executado com uma conta de serviço com privilégios adequados para ler o secret do servidor da API. Monitore o status da transferência com comandos kubectl padrão que operam no job.

Considere os detalhes a seguir ao transferir o armazenamento em blocos para o armazenamento de objetos:

  • Por padrão, os links simbólicos seguem e são replicados para o armazenamento de objetos, mas uma cópia detalhada em vez de superficial é realizada. Após a restauração, ela destrói os links simbólicos.
  • Assim como na replicação de armazenamento de objetos, a clonagem em um subdiretório do bucket é destrutiva. Verifique se o bucket está disponível exclusivamente para o volume.

Restaurar do repositório de objetos para o armazenamento em blocos

Alocar um PV

Para restaurar o armazenamento em blocos de um endpoint de armazenamento de objetos, siga estas etapas:

  1. Alocar um volume permanente para o destino na restauração. Use um PVC para alocar o volume, conforme mostrado no exemplo a seguir:

    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. Verifique o status do PVC:

    kubectl get pvc restore-pvc -n restore-ns
    

    Depois que o PVC estiver em um estado Bound, ele estará pronto para ser consumido no pod que o reidrata.

  3. Se um conjunto com estado consumir o PV, você precisará corresponder aos PVCs do StatefulSet renderizado. Os pods que o StatefulSet produz consomem os volumes hidratados. O exemplo a seguir mostra modelos de declaração de volume em um StatefulSet chamado ss.

      volumeClaimTemplates:
      - metadata:
          name: pvc-name
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "default"
          resources:
            requests:
              storage: 1Gi
    
  4. Pré-aloque PVCs com nomes como ss-pvc-name-0 e ss-pvc-name-1 para garantir que os pods resultantes consumam os volumes pré-alocados.

Hidratar o PV

Depois que o PVC estiver vinculado a um PV, inicie o job para preencher o 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

Depois que o job terminar de ser executado, os dados do bucket de armazenamento de objetos vão preencher o volume. Um pod separado pode consumir os dados usando os mesmos mecanismos padrão para montar um volume.