העברת נתוני MySQL מ-Persistent Disk ל-Hyperdisk ב-GKE

במדריך הזה מוסבר איך להעביר נתונים קיימים של MySQL מדיסק מתמיד (PD) אל Hyperdisk ב-Google Kubernetes Engine כדי לשדרג את ביצועי האחסון. ל-Hyperdisk יש IOPS ותפוקה גבוהים יותר מאשר ל-Persistent Disk, מה שיכול לשפר את הביצועים של MySQL על ידי הפחתת זמן האחזור של שאילתות וטרנזקציות במסד הנתונים. אתם יכולים להשתמש בתמונות מצב של דיסקים כדי להעביר את הנתונים לסוגי דיסקים שונים, בהתאם לתאימות של סוג המכונה. לדוגמה, אמצעי אחסון ב-Hyperdisk תואמים רק לסוגי מכונות מסוימים מהדור השלישי, הרביעי ואילך, כמו N4, שלא תומכים ב-Persistent Disks. מידע נוסף מופיע במאמר בנושא סדרות מכונות.

כדי להדגים את ההעברה מ-Persistent Disk ל-Hyperdisk, במדריך הזה נעשה שימוש במסד הנתונים Sakila כדי לספק מערך נתונים לדוגמה. ‫Sakila הוא מסד נתונים לדוגמה שמסופק על ידי MySQL, ואפשר להשתמש בו כסכימה למדריכים ולדוגמאות. הוא מייצג חנות בדיונית להשכרת DVD וכולל טבלאות של סרטים, שחקנים, לקוחות והשכרות.

המדריך הזה מיועד למומחי אחסון ולאדמינים של אחסון שיוצרים ומקצים אחסון, ומנהלים את אבטחת הנתונים והגישה לנתונים. כדי לקבל מידע נוסף על תפקידים נפוצים ועל משימות לדוגמה שאנחנו מתייחסים אליהן ב Google Cloud תוכן, אפשר לעיין במאמר תפקידים נפוצים של משתמשי GKE ומשימות.

ארכיטקטורת פריסה

התרשים הבא ממחיש את תהליך המיגרציה מ-Persistent Disk ל-Hyperdisk.

  • אפליקציית MySQL פועלת במאגר צמתים של GKE עם סוגי מכונות N2, והנתונים שלה מאוחסנים ב-SSD של Persistent Disk.
  • כדי לשמור על עקביות הנתונים, האפליקציה מוקטנת כדי למנוע כתיבה חדשה.
  • נוצרת תמונת מצב של הדיסק הקשיח, שמשמשת כגיבוי מלא של הנתונים בנקודת זמן מסוימת.
  • מבוצעת הקצאה של Hyperdisk חדש מהתמונה, ומופעל מופע חדש של MySQL במאגר צמתים נפרד מסוג N4 שתואם ל-Hyperdisk. המופע החדש מצורף ל-Hyperdisk החדש שנוצר, וכך מסתיים המעבר לאחסון עם ביצועים טובים יותר.
דיאגרמת ארכיטקטורה שמראה העברה של נתוני MySQL מ-Persistent Disk ל-Hyperdisk באמצעות תמונת מצב.
איור 1: העברת נתונים מ-MySQL מ-Persistent Disk ל-Hyperdisk באמצעות קובץ snapshot.

מטרות

במדריך הזה תלמדו איך:

  • פריסת אשכול MySQL.
  • מעלים קבוצת נתונים לבדיקה.
  • יוצרים תמונת מצב של הנתונים.
  • יוצרים Hyperdisk מקובץ ה-snapshot.
  • מתחילים אשכול MySQL חדש במאגר צמתים מסוג מכונה N4 עם Hyperdisk.
  • כדי לוודא שההעברה בוצעה בהצלחה, בודקים את תקינות הנתונים.

עלויות

במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:

  • GKE
  • Compute Engine, which includes:
    • Storage capacity provisioned for both Persistent Disk and Hyperdisk.
    • Storage costs for the snapshots.

כדי ליצור הערכת עלויות בהתאם לשימוש החזוי, אתם יכולים להשתמש במחשבון התמחור.

משתמשים חדשים של Google Cloud ? יכול להיות שאתם זכאים לתקופת ניסיון בחינם.

לפני שמתחילים

  1. נכנסים לחשבון Google Cloud . אנחנו ממליצים למשתמשים חדשים ב- Google Cloud ליצור חשבון כדי שיוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Compute Engine, GKE, Identity and Access Management Service Account Credentials APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Compute Engine, GKE, Identity and Access Management Service Account Credentials APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  8. צריך לוודא שיש לכם בפרויקט את התפקיד או התפקידים הבאים: roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin

    בדיקת התפקידים

    1. נכנסים לדף IAM במסוף Google Cloud .

      כניסה לדף IAM
    2. בוחרים את הפרויקט.
    3. בעמודה Principal, מחפשים את כל השורות שמזהות אתכם או קבוצה שאתם נכללים בה. כדי לדעת באילו קבוצות אתם נכללים, פנו לאדמין.

    4. בודקים את העמודה Role בכל השורות שבהן מצוין או מופיע השם שלכם, כדי לראות אם רשימת התפקידים כוללת את התפקידים הנדרשים.

    מתן התפקידים

    1. נכנסים לדף IAM במסוף Google Cloud .

      כניסה לדף IAM
    2. בוחרים את הפרויקט.
    3. לוחצים על Grant access.
    4. בשדה New principals, מזינים את מזהה המשתמש. ‫ בדרך כלל מזהה המשתמש הוא כתובת האימייל של חשבון Google.

      ‫
    5. לוחצים על Select a role ומחפשים את התפקיד.
    6. כדי לתת עוד תפקידים, לוחצים על Add another role ומוסיפים אותם.
    7. לוחצים על Save.

הגדרת Cloud Shell

  1. מפעילים את Cloud Shell במסוף Google Cloud .

    הפעלת Cloud Shell

    בחלק התחתון של Google Cloud המסוף יתחיל סשן של Cloud Shell ותופיע הודעה של שורת הפקודה. Cloud Shell היא סביבת מעטפת שבה ה-CLI של Google Cloud מותקן ומוגדרים ערכים לפרויקט הקיים. הסשן יופעל תוך כמה שניות.

  2. יתחיל סשן של Cloud Shell ותופיע הודעה של שורת הפקודה. הסשן יופעל תוך כמה שניות.

  3. מגדירים את פרויקט ברירת המחדל:

      gcloud config set project PROJECT_ID
    

    מחליפים את PROJECT_ID במזהה הפרויקט.

הכנת הסביבה

  1. ב-Cloud Shell, מגדירים את משתני הסביבה של הפרויקט, המיקום והקידומת של האשכול.

    export PROJECT_ID=PROJECT_ID
    export EMAIL_ADDRESS=EMAIL_ADDRESS
    export KUBERNETES_CLUSTER_PREFIX=offline-hyperdisk-migration
    export LOCATION=us-central1-a
    

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

    • ‫PROJECT_ID: Google Cloud מזהה הפרויקט.
    • ‫EMAIL_ADDRESS: כתובת האימייל שלכם.
    • ‫LOCATION: האזור שבו רוצים ליצור את משאבי הפריסה. לצורך המדריך הזה, משתמשים באזור us-central1-a.
  2. משכפלים את מאגר המקורות של הקוד לדוגמה מ-GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  3. עוברים לספרייה offline-hyperdisk-migration כדי להתחיל ליצור משאבי פריסה:

    cd kubernetes-engine-samples/databases/offline-hyperdisk-migration
    

יצירת אשכול GKE ומאגרי צמתים

כדי לפשט את המדריך, אנחנו משתמשים באשכול של תחום מוגדר, כי נפחי Hyperdisk הם משאבים של תחום מוגדר וניתן לגשת אליהם רק בתחום אחד.

  1. יוצרים אשכול GKE אזורי:

    gcloud container clusters create ${KUBERNETES_CLUSTER_PREFIX}-cluster \
        --location ${LOCATION} \
        --node-locations ${LOCATION} \
        --shielded-secure-boot \
        --shielded-integrity-monitoring \
        --machine-type "e2-micro" \
        --num-nodes "1"
    
  2. מוסיפים מאגר צמתים עם סוג מכונה N2 לפריסת MySQL הראשונית:

    gcloud container node-pools create regular-pool \
        --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
        --machine-type n2-standard-4 \
        --location ${LOCATION} \
        --num-nodes 1
    
  3. מוסיפים מאגר צמתים עם סוג מכונה N4 ב-Hyperdisk, שבו פריסת MySQL תועבר ותופעל:

    gcloud container node-pools create hyperdisk-pool \
        --cluster ${KUBERNETES_CLUSTER_PREFIX}-cluster \
        --machine-type n4-standard-4 \
        --location ${LOCATION} \
        --num-nodes 1
    
  4. מתחברים לאשכול:

    gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --location ${LOCATION}
    

פריסת MySQL ב-Persistent Disk

בקטע הזה פורסים מופע MySQL שמשתמש ב-Persistent Disk לאחסון, וטוענים בו נתונים לדוגמה.

  1. יצירה והחלה של StorageClass ל-Hyperdisk. הערך של StorageClass ישמש בהמשך המדריך.

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: balanced-storage
    provisioner: pd.csi.storage.gke.io
    volumeBindingMode: WaitForFirstConsumer
    allowVolumeExpansion: true
    parameters:
      type: hyperdisk-balanced
      provisioned-throughput-on-create: "250Mi"
      provisioned-iops-on-create: "7000"
    kubectl apply -f manifests/01-storage-class/storage-class-hdb.yaml
    
  2. יוצרים ומפעילים מכונת MySQL שכוללת קשרי צומת כדי לוודא ש-Pods מתוזמנים בצמתים של regular-pool, ומקצים נפח SSD של Persistent Disk.

    apiVersion: v1
    kind: Service
    metadata:
      name: regular-mysql
      labels:
        app: mysql
    spec:
      ports:
        - port: 3306
      selector:
        app: mysql
      clusterIP: None
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mysql-pv-claim
      labels:
        app: mysql
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 30Gi
      storageClassName: premium-rwo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: existing-mysql
      labels:
        app: mysql
    spec:
      selector:
        matchLabels:
          app: mysql
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: mysql
        spec:
          containers:
          - image: mysql:8.0
            name: mysql
            env:
            - name: MYSQL_ROOT_PASSWORD
              value: migration
            - name: MYSQL_DATABASE
              value: mysql
            - name: MYSQL_USER
              value: app
            - name: MYSQL_PASSWORD
              value: migration
            ports:
            - containerPort: 3306
              name: mysql
            volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
          affinity: 
            nodeAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 1
                preference:
                  matchExpressions:
                  - key: "node.kubernetes.io/instance-type"
                    operator: In
                    values:
                    - "n2-standard-4"
          volumes:
          - name: mysql-persistent-storage
            persistentVolumeClaim:
              claimName: mysql-pv-claim
    kubectl apply -f manifests/02-mysql/mysql-deployment.yaml
    

    קובץ המניפסט הזה יוצר פריסה ושירות של MySQL, עם דיסק אחסון מתמיד (persistent disk) שהוקצה באופן דינמי לאחסון נתונים. הסיסמה של המשתמש root היא migration.

  3. פורסים Pod של לקוח MySQL כדי לטעון נתונים, ומאמתים את העברת הנתונים:

    apiVersion: v1
    kind: Pod
    metadata:
      name: mysql-client
    spec:
      containers:
      - name: main
        image: mysql:8.0
        command: ["sleep", "360000"]
        resources:
          requests:
            memory: 1Gi
            cpu: 500m
          limits:
            memory: 1Gi
            cpu: "1"
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: migration
    kubectl apply -f manifests/02-mysql/mysql-client.yaml
    kubectl wait pods mysql-client --for condition=Ready --timeout=300s
    
  4. מתחברים ל-Pod של הלקוח:

    kubectl exec -it mysql-client -- bash
    
  5. ממעטפת ה-Pod של הלקוח, מורידים ומייבאים את מערך הנתונים לדוגמה של Sakila:

    # Download the dataset
    curl --output dataset.tgz "https://downloads.mysql.com/docs/sakila-db.tar.gz"
    
    # Extract the dataset
    tar -xvzf dataset.tgz -C /
    
    # Import the dataset into MySQL (the password is "migration").
    mysql -u root -h regular-mysql.default -p
        SOURCE /sakila-db/sakila-schema.sql;
        SOURCE /sakila-db/sakila-data.sql;
    
  6. בודקים שהנתונים יובאו:

    USE sakila;
    SELECT      table_name,      table_rows  FROM      INFORMATION_SCHEMA.TABLES  WHERE TABLE_SCHEMA = 'sakila';
    

    בפלט מוצגת רשימה של טבלאות עם מספר השורות.

    | TABLE_NAME                 | TABLE_ROWS |
    +----------------------------+------------+
    | actor                      |        200 |
    | actor_info                 |       NULL |
    | address                    |        603 |
    | category                   |         16 |
    | city                       |        600 |
    | country                    |        109 |
    | customer                   |        599 |
    | customer_list              |       NULL |
    | film                       |       1000 |
    | film_actor                 |       5462 |
    | film_category              |       1000 |
    | film_list                  |       NULL |
    | film_text                  |       1000 |
    | inventory                  |       4581 |
    | language                   |          6 |
    | nicer_but_slower_film_list |       NULL |
    | payment                    |      16086 |
    | rental                     |      16419 |
    | sales_by_film_category     |       NULL |
    | sales_by_store             |       NULL |
    | staff                      |          2 |
    | staff_list                 |       NULL |
    | store                      |          2 |
    +----------------------------+------------+
    23 rows in set (0.01 sec)
    
  7. יוצאים מהסשן של mysql:

    exit;
    
  8. יוצאים מהמעטפת של Pod הלקוח:

    exit
    
  9. משיגים את השם של PersistentVolume‏ (PV) שנוצר בשביל MySQL ושומרים אותו במשתנה סביבה:

    export PV_NAME=$(kubectl get pvc mysql-pv-claim -o jsonpath='{.spec.volumeName}')
    

העברת הנתונים לנפח Hyperdisk

עכשיו יש לכם עומס עבודה של MySQL עם נתונים שמאוחסנים בנפח SSD של Persistent Disk. בקטע הזה מתואר איך מעבירים את הנתונים האלה לנפח Hyperdisk באמצעות תמונת מצב. בנוסף, הגישה הזו להעברה שומרת את עוצמת הקול המקורית של Persistent Disk, כך שאם צריך, אפשר לחזור לשימוש במופע המקורי של MySQL.

  1. אפשר ליצור תמונות מצב מדיסקים בלי לנתק אותם מעומסי עבודה, אבל כדי להבטיח את תקינות הנתונים ב-MySQL, צריך להפסיק את כל פעולות הכתיבה החדשות לדיסק במהלך יצירת תמונת המצב. מצמצמים את הפריסה של MySQL ל-0 רפליקות כדי להפסיק את פעולות הכתיבה:

    kubectl scale deployment existing-mysql --replicas=0
    
  2. יוצרים קובץ snapshot מדיסק האחסון המתמיד הקיים:

    gcloud compute disks snapshot ${PV_NAME} --zone=${LOCATION} --snapshot-names=original-snapshot --description="snapshot taken from pd-ssd"
    
  3. יוצרים נפח Hyperdisk חדש בשם mysql-recovery מקובץ ה-snapshot:

    gcloud compute disks create mysql-recovery --project=${PROJECT_ID} \
        --type=hyperdisk-balanced \
        --size=150GB --zone=${LOCATION} \
        --source-snapshot=projects/${PROJECT_ID}/global/snapshots/original-snapshot
    
  4. מעדכנים את קובץ המניפסט של ה-PV ששוחזר עם מזהה הפרויקט:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: backup
    spec:
      storageClassName: balanced-storage
      capacity:
        storage: 150G
      accessModes:
        - ReadWriteOnce
      claimRef:
        name: hyperdisk-recovery
        namespace: default
      csi:
        driver: pd.csi.storage.gke.io
        volumeHandle: projects/PRJCTID/zones/us-central1-a/disks/mysql-recovery
        fsType: ext4
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      namespace: default
      name: hyperdisk-recovery
    spec:
      storageClassName: balanced-storage
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 150G
    sed -i "s/PRJCTID/$PROJECT_ID/g" manifests/02-mysql/restore_pv.yaml
    
  5. יוצרים את PersistentVolume ‏ (PVC) ואת PersistentVolumeClaim מה-Hyperdisk החדש:

    kubectl apply -f manifests/02-mysql/restore_pv.yaml
    

אימות העברת הנתונים

פריסת מכונת MySQL חדשה שמשתמשת בנפח Hyperdisk שנוצר לאחרונה. ה-Pod הזה יתוזמן במאגר הצמתים hyperdisk-pool שמורכב מצומתי N4.

  1. פורסים את מופע MySQL החדש:

    apiVersion: v1
    kind: Service
    metadata:
      name: recovered-mysql
      labels:
        app: new-mysql
    spec:
      ports:
        - port: 3306
      selector:
        app: new-mysql
      clusterIP: None
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: new-mysql
      labels:
        app: new-mysql
    spec:
      selector:
        matchLabels:
          app: new-mysql
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: new-mysql
        spec:
          containers:
          - image: mysql:8.0
            name: mysql
            env:
            - name: MYSQL_ROOT_PASSWORD
              value: migration
            - name: MYSQL_DATABASE
              value: mysql
            - name: MYSQL_USER
              value: app
            - name: MYSQL_PASSWORD
              value: migration
            ports:
            - containerPort: 3306
              name: mysql
            volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
          affinity: 
            nodeAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 1
                preference:
                  matchExpressions:
                  - key: "cloud.google.com/gke-nodepool"
                    operator: In
                    values:
                    - "hyperdisk-pool"      
          volumes:
          - name: mysql-persistent-storage
            persistentVolumeClaim:
              claimName: hyperdisk-recovery
    kubectl apply -f manifests/02-mysql/recovery_mysql_deployment.yaml
    
  2. כדי לאמת את תקינות הנתונים, מתחברים שוב ל-Pod של לקוח MySQL:

    kubectl exec -it mysql-client -- bash
    
  3. בתוך ה-Pod של הלקוח, מתחברים למסד הנתונים החדש של MySQL (recovered-mysql.default) ומאמתים את הנתונים. הסיסמה היא migration.

    mysql -u root -h recovered-mysql.default -p
    USE sakila;
    SELECT table_name, table_rows FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'sakila';
    

    הנתונים צריכים להיות זהים לנתונים במופע המקורי של MySQL בנפח של Persistent Disk.

  4. יציאה מהסשן של mysql:

    exit;
    
  5. יוצאים מהמעטפת של Pod הלקוח:

    exit
    

הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, אפשר למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים הנפרדים.

מחיקת הפרויקט

    כדי למחוק פרויקט ב- Google Cloud :

    gcloud projects delete PROJECT_ID

מחיקת משאבים ספציפיים

אם השתמשתם בפרויקט קיים ואתם לא רוצים למחוק אותו, אתם יכולים למחוק את המשאבים הבודדים:

  1. מגדירים משתני סביבה לניקוי ומאחזרים את השם של נפח האחסון המתמיד (Persistent Disk) שנוצר על ידי mysql-pv-claim PersistentVolumeClaim:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=offline-hyperdisk-migration
    export location=us-central1-a
    export PV_NAME=$(kubectl get pvc mysql-pv-claim -o jsonpath='{.spec.volumeName}')
    

    מחליפים את PROJECT_ID במזהה הפרויקט.

  2. מחיקת תמונת המצב:

    gcloud compute snapshots delete original-snapshot --quiet
    
  3. מוחקים את אשכול GKE:

    gcloud container clusters delete ${KUBERNETES_CLUSTER_PREFIX}-cluster --location=${LOCATION} --quiet
    
  4. מוחקים את הכרכים של Persistent Disk ו-Hyperdisk:

    gcloud compute disks delete ${PV_NAME} --zone=${LOCATION} --quiet
    gcloud compute disks delete mysql-recovery --zone=${LOCATION} --quiet
    

המאמרים הבאים