העברת נתונים

מכשיר ה-appliance של Google Distributed Cloud (GDC) במודל Air-gapped מעביר נתונים שרירותיים אל סביבת Google Distributed Cloud במודל Air-gapped וממנה. אפשר להתחיל העברות באופן ידני או להגדיר שהן יתבצעו אוטומטית במרווחים קבועים.

העברות לדוגמה:

  • הורדה של עדכוני תוכנה או עומסי עבודה מעודכנים של לקוחות
  • העלאה של נתוני לקוחות, מדדי מכשירים או יומני אבטחה, ביקורת ותפעול של מכשירים
  • גיבוי תמונות מצב של נתונים

כלי העברת האחסון מעביר נתונים ומופץ בתמונה לשימוש בקונטיינרים פועלים באשכול.

מקורות נתונים

הכלי להעברת נתונים מאפשר גמישות בתנאי ההפעלה של מכשיר GDC עם air gap. ממשקי API שתואמים ל-S3 יכולים לגשת ליעדי אחסון פנימיים וחיצוניים. הכלי תומך גם במערכת קבצים מקומית ובמקורות של Cloud Storage.

האחריות על שמירת השליטה במפתחות הגישה ובכל אישורי הגישה, הסודות או הנתונים הרגישים האחרים שנדרשים לאימות כדי לחבר את מכשיר GDC עם בידוד פיזי לרשתות חיצוניות מוטלת על המפעיל. האחריות להגדרת הרשת החיצונית חלה גם על המפעיל.

במאמר בנושא יצירת קטגוריות אחסון מוסבר איך ליצור אחסון חיצוני ולקבל אליו גישה.

אחסון מקומי

האחסון המקומי נמצא בסביבת הקונטיינר של ה-Pod וכולל את מערכת הקבצים הזמנית או את אמצעי האחסון המחוברים. לחשבון השירות שמשויך ל-pod צריכה להיות גישה לכל יעדי הטעינה כשמטעינים נפחים.

אחסון ב-S3

אפשר לגשת לאחסון הזמין ברשת דרך S3 Compatible API. השירות יכול להיות חיצוני או חשוף רק בתוך רשת האשכול. צריך לספק כתובת URL נגישה ופרטי כניסה סטנדרטיים שמוצמדים באמצעות Kubernetes Secret.

הגישה לנתונים מוגדרים באחסון אובייקטים ובמערכות מרובות צמתים מתבצעת דרך S3 API. בקטעים הרלוונטיים מוסבר איך להגדיר אחסון מרובה צמתים ואחסון אובייקטים במכשיר GDC עם air gap.

אחסון בענן

חובה לציין כתובת URL שאפשר לגשת אליה ופרטי כניסה סטנדרטיים שמוגדרים באמצעות Secret.

אם ניגשים לקטגוריה של Cloud Storage עם אמצעי בקרה אחידים לגישה, צריך להגדיר את הדגל --bucket-policy-only לערך true.

פרטי כניסה

כדי להשתמש בשירות Storage Transfer Service עבור הגדרות של מקור או יעד ב-S3 או ב-GCS, צריך להגדיר סוד של Kubernetes. אפשר לספק אותם באמצעות חשבון שירות מרוחק או חשבון משתמש.

כשמשתמשים ב-Secrets בהגדרות של Job או CronJob, צריך לצרף את JobSpec ל-Kubernetes ServiceAccount שיש לו גישה ל-Secrets.

יוצרים ServiceAccount שמשמש להעברה, ואז מוסיפים הרשאות ל-ServiceAccount כדי לקרוא ולכתוב סודות באמצעות תפקידים וקישורים בין תפקידים. אתם יכולים לבחור שלא ליצור ServiceAccount אם ל-ServiceAccount של מרחב השמות שמוגדר כברירת מחדל או ל-ServiceAccount בהתאמה אישית כבר יש הרשאות.

  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

חשבונות שירות מרחוק

כדי לקבל פרטי כניסה של חשבון שירות ב-Cloud Storage לצורך העברה, אפשר לעיין במאמר https://developers.google.com/workspace/guides/create-credentials#create_credentials_for_a_service_account. פרטי הכניסה האלה צריכים להיות מאוחסנים בסוד בשדה service-account-key.

לדוגמה:

apiVersion: v1
data:
  service-account-key: BASE_64_ENCODED_VERSION_OF_CREDENTIAL_FILE_CONTENTS
kind: Secret
metadata:
  name: gcs-secret
  namespace: NAMESPACE
type: Opaque

חשבונות משתמשים

אתם יכולים להשתמש בחשבון משתמש לאימות עם קטגוריות תואמות ל-S3, ולא עם קטגוריות של Cloud Storage. צריך לציין את הארגומנט --src_type או --dst_type כ-s3.

kubectl create secret -n NAMESPACE generic S3_CREDENTIAL_SECRET_NAME \
    --from-literal=access-key-id=ACCESS_KEY_ID
    --from-literal=access-key=ACCESS_KEY

מחליפים את מה שכתוב בשדות הבאים:

  • NAMESPACE: השם של מרחב השמות שבו תיצרו את הגדרת המשימה.
  • SECRET_NAME: השם של הסוד שאתם יוצרים.
  • ACCESS_KEY_ID: הערך שמופיע בשדה Access Key במסוף Google Cloud . כשמגדירים את Object Storage, השם של המפתח הזה הוא access-key-id.
  • ACCESS_KEY: הערך שמופיע בשדה Secret במסוף Google Cloud . כשמגדירים את Object Storage, זהו המפתח הסודי או הסוד.

אישורים

צריך לספק אישורים לאימות במשימה עם סוד של Kubernetes שמכיל מפתח נתונים ca.crt.

  apiVersion: v1
  kind: Secret
  metadata:
    name: SRC_CERTIFICATE_SECRET_NAME
    namespace: NAMESPACE
  data:
    ca.crt : BASE_64_ENCODED_SOURCE_CERTIFICATE
  ---
  apiVersion: v1
  kind: Secret
  metadata:
    name: DST_CERTIFICATE_SECRET_NAME
    namespace: NAMESPACE
  data:
    ca.crt : BASE_64_ENCODED_DESTINATION_CERTIFICATE # Can be same OR different than source certificate.

אפשר לספק אישורים באמצעות הפניה לכלי עם הארגומנטים src_ca_certificate_reference ו-dst_ca_certificate_reference בפורמט NAMESPACE/SECRET_NAME. לדוגמה:

...
      containers:
      - name: storage-transfer-pod
        image: gcr.io/private-cloud-staging/storage-transfer:latest
        command:
        - /storage-transfer
        args:
        ...
        - --src_ca_certificate_reference=NAMESPACE/SRC_CERTIFICATE_SECRET_NAME
        - --dst_ca_certificate_reference=NAMESPACE/DST_CERTIFICATE_SECRET_NAME

במקרה של אחסון S3 במכשיר, אפשר להשתמש ישירות בסוד trust-store-root-ext כאישור CA. לדוגמה:

containers:
      - name: storage-transfer-pod
        image: gcr.io/private-cloud-staging/storage-transfer:latest
        command:
        - /storage-transfer
        args:
        - --src_type=s3
        - --src_ca_certificate_reference=NAMESPACE/trust-store-root-ext

אופציונלי: הגדרה של LoggingTarget כדי לראות יומנים ב-Loki

כברירת מחדל, יומנים של משימות ניתנים לצפייה רק במשאבי Kubernetes, ולא זמינים בחבילת הכלים למעקב אחרי נראות. כדי שיומנים יהיו זמינים לצפייה, צריך להגדיר LoggingTarget.

  apiVersion: logging.gdc.goog/v1alpha1
  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:
        - data-transfer-job # Choose the prefix here that matches your transfer job name
    serviceName: transfer-service

הגדרת משרה מובנית

המשתמשים מנהלים את משאבי המשרות שלהם. להעברות נתונים חד-פעמיות, מגדירים Job. ה-Job יוצר Pod להרצת קונטיינר של העברת נתונים.

דוגמה למשרה:

apiVersion: batch/v1
kind: Job
metadata:
  name: data-transfer-job
  namespace: NAMESPACE
spec:
  template:
    spec:
      restartPolicy: Never
      serviceAccountName: transfer-service-account,
      containers:
      - name: storage-transfer-pod
        image: gcr.io/private-cloud-staging/storage-transfer:latest
        command:
        - /storage-transfer
        args:
        - --src_path=/src
        - --src_type=local
        - --dst_endpoint=https://your-dst-endpoint.com
        - --dst_credentials=NAMESPACE/CREDENTIAL_SECRET_NAME
        - --dst_path=/FULLY_QUALIFIED_BUCKET_NAME/BUCKET_PATH
        - --dst_type=gcs
        - --bucket_policy_only=true
        - --bandwidth_limit=10M #Optional of the form '10K', '100M', '1G' bytes per second
        volumeMounts:
        - mountPath: /src
          name: data
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: data-transfer-source

הגדרה של משימת Cron מובנית

המשתמשים מנהלים את משאבי CronJob המוגדרים שלהם. שימוש ב-CronJob מובנה מאפשר לתזמן העברות נתונים באופן קבוע.

דוגמה ל-CronJob שמאפשר העברת נתונים אוטומטית:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: data-transfer-cronjob
  namespace: NAMESPACE
spec:
  schedule: "* * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: transfer-service-account
          containers:
          - name: storage-transfer-pod
            image: gcr.io/private-cloud-staging/storage-transfer:latest
            command:
            - /storage-transfer
            args:
            - --src_path=LOCAL_PATH
            - --src_type=local
            - --dst_endpoint=https://your-dst-endpoint.com
            - --dst_credentials=NAMESPACE/CREDENTIAL_SECRET_NAME
            - --dst_path=/FULLY_QUALIFIED_BUCKET_NAME/BUCKET_PATH
            - --dst_type=gcs
            - --bucket_policy_only=true
            volumeMounts:
            - mountPath: LOCAL_PATH
              name: source
          restartPolicy: Never
          volumes:
          - name: source
            persistentVolumeClaim:
              claimName: data-transfer-source

‫Google ממליצה להגדיר את concurrencyPolicy לערך Forbid כדי למנוע התנגשות נתונים. ה-CronJob, ה-Secret וה-PersistentVolumeClaim צריכים להיות באותו מרחב שמות.

קביעת סדר עדיפויות למשימות שקשורות לנתונים

יש כמה דרכים להגדיר עדיפות למשימות עיבוד נתונים, והן לא סותרות אחת את השנייה. אפשר להגדיר תזמונים פחות תכופים של משימות בהגדרה של CronJob.

אפשר גם להגדיר את סדר העבודות באמצעות InitContainers (https://kubernetes.io/docs/concepts/workloads/pods/init-containers/), שתמיד פועלים לפי סדר ההגדרה. עם זאת, כל מאגרי התגים חייבים לפעול בהצלחה. אפשר להשתמש ב-InitContainers כדי לתת עדיפות גבוהה יותר למשימה מסוימת, או כדי לנהל את התחרות על הנתונים על ידי הגדרה של שני InitContainers או יותר עם הגדרות משוכפלות של מקור ויעד.

דוגמה ל-jobTemplate שמעביר נתונים לפי סדר:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: ordered-data-transfer-cronjob
  namespace: NAMESPACE
spec:
  schedule: "* * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: job-complete
            image: whalesay
            command: ["sh", "-c", "echo Job Completed."]
          initContainers:
          - name: A-to-B
            image: gcr.io/private-cloud-staging/storage-transfer:latest
            command: [/storage-transfer]
            args:
            - --src_type=s3
            - --src_endpoint=ENDPOINT_A
            - --src_path=/example-bucket
            - --src_credentials=NAMESPACE/CREDENTIAL_SECRET_NAME
            - --src_ca_certificate_reference=NAMESPACE/SRC_CERTIFICATE_SECRET_NAME
            - --dst_type=s3
            - --dst_endpoint=ENDPOINT_B
            - --dst_credentials=NAMESPACE/CREDENTIAL_SECRET_NAME
            - --dst_ca_certificate_reference=NAMESPACE/DST_CERTIFICATE_SECRET_NAME
            - --dst_path=/example-bucket
          - name: B-to-A
            image: gcr.io/private-cloud-staging/storage-transfer:latest
            command: [/storage-transfer]
            args:
            - --src_type=s3
            - --src_endpoint=ENDPOINT_B
            - --src_credentials=NAMESPACE/CREDENTIAL_SECRET_NAME
            - --src_ca_certificate_reference=NAMESPACE/SRC_CERTIFICATE_SECRET_NAME
            - --src_path=/example-bucket
            - --dst_type=s3
            - --dst_endpoint=ENDPOINT_A
            - --dst_credentials=NAMESPACE/CREDENTIAL_SECRET_NAME
            - --dst_ca_certificate_reference=NAMESPACE/DST_CERTIFICATE_SECRET_NAME
            - --dst_path=/example-bucket

קונטיינר A-to-B פועל לפני B-to-A. בדוגמה הזו מושגים גם סנכרון דו-כיווני וגם סדר משימות.