שימוש בקובץ אימג' מותאם אישית של מערכת ההפעלה

אתם יכולים להשתמש בקובץ אימג' מותאם אישית של מערכת ההפעלה למכונות הווירטואליות של ה-TPU כדי לטעון מראש תוכנה, להשתמש בהפצה ספציפית של מערכת ההפעלה או להחיל שינויים מותאמים אישית בליבה (kernel). כדי ליצור קובץ אימג' בהתאמה אישית, צריך לבצע שינויים ספציפיים במערכת במהלך תהליך היצירה של קובץ האימג', ולהגדיר את קובץ האימג' כך שיטפל במשימות בזמן ההפעלה שנדרשות לפונקציונליות של ה-TPU.

אם אתם משתמשים בקובץ אימג' של מערכת הפעלה בהתאמה אישית עם יחידות TPU, חשוב לזכור את כתבי הוויתור הבאים:

  • ‫Google מספקת קובצי אימג' של Ubuntu עם תמיכה לטווח ארוך (LTS) שמותאמים כברירת מחדל ל-TPU. השינויים במערכת ההפעלה שמפורטים בדף הזה אומתו רק לתמונות Ubuntu LTS שמותאמות ל-TPU ונתמכות על ידי Google.
  • אתם אחראים להסיק מהם השינויים הנדרשים במערכת ההפעלה לכל הפצה אחרת של מערכת ההפעלה או לתמונות בהתאמה אישית. ‫Google לא מבטיחה שהשינויים ב-Ubuntu שמפורטים בדף הזה יפעלו עם הפצות אחרות של מערכת ההפעלה או עם קובץ אימג' אחר של Ubuntu עם ליבה מותאמת אישית.
  • ‫Google לא יוצרת או מספקת בדיקות לקובצי אימג' של מערכות הפעלה, מלבד קובצי האימג' של Ubuntu LTS שמותאמים כברירת מחדל ל-TPU. אתם צריכים ליצור ולבדוק את קובץ האימג' של מערכת ההפעלה בהתאמה אישית.

למידע נוסף על קובצי האימג' של Ubuntu LTS שמותאמים כברירת מחדל ל-TPU, קראו את המאמר קובצי אימג' של מערכת ההפעלה ל-TPU.

דרישות מוקדמות

בתמונת הבסיס צריכים להיות מותקנים הרכיבים הבאים:

  • Docker
  • ‫ethtool, גרסה 6.7 ואילך אם משתמשים ב-TPU v6e או ב-TPU7x
  • ‫Python 3 עם החבילות PyYAML ו-requests, שזמינות ב-Ubuntu בתור python3-yaml ו-python3-requests
  • ‫CLI של gcloud

במכונות וירטואליות מסוג TPU7x, קובץ האימג' הבסיסי צריך להשתמש בגרסה 6.8 לפחות של ליבת Linux של מערכת ההפעלה של האורח.

שינויים בתהליך יצירת התמונה

מבצעים את השינויים הבאים בזמן שיוצרים את קובץ האימג' בהתאמה אישית של Ubuntu.

השבתת שדרוגים אוטומטיים

משביתים ומסירים את unattended-upgrades כדי שעדכוני חבילות ברקע לא יחזיקו את הנעילה של dpkg או יפריעו לעומסי העבודה של ה-TPU:

echo 'APT::Periodic::Unattended-Upgrade "0";' > /etc/apt/apt.conf.d/99cloudtpuconf
DEBIAN_FRONTEND=noninteractive apt-get -y purge unattended-upgrades

קישור מכשירי TPU ל-VFIO

כדי לאפשר למערכת ההפעלה של המכונה להתחבר לחומרת ה-TPU, צריך לקשר את מכשירי ה-TPU למנהל ההתקן vfio-pci.

  1. יוצרים קובץ כללים של udev בשם 99-tpu-vfiopci.rules ב-/etc/udev/rules.d/:

    # Rules for binding vfio-enabled TPU devices to vfio-pci.
    
    # v5p
    SUBSYSTEM=="pci", ACTION=="add", ATTRS{vendor}=="0x1ae0", ATTRS{device}=="0x0062", ATTRS{subsystem_vendor}=="0x1ae0", ATTRS{subsystem_device}=="0x00ad", DRIVER!="vfio-pci", TAG+="bind_to_vfio_pci"
    
    # v6e
    SUBSYSTEM=="pci", ACTION=="add", ATTRS{vendor}=="0x1ae0", ATTRS{device}=="0x006f", ATTRS{subsystem_vendor}=="0x1ae0", ATTRS{subsystem_device}=="0x00d1", DRIVER!="vfio-pci", TAG+="bind_to_vfio_pci"
    
    # TPU7x
    SUBSYSTEM=="pci", ACTION=="add", ATTRS{vendor}=="0x1ae0", ATTRS{device}=="0x0076", ATTRS{subsystem_vendor}=="0x1ae0", ATTRS{subsystem_device}=="0x00f2", DRIVER!="vfio-pci", TAG+="bind_to_vfio_pci"
    
    # Bind all 'bind_to_vfio_pci' tagged devices to vfio-pci.
    TAG=="bind_to_vfio_pci", RUN+="/lib/udev/bind_to_vfio_pci.sh $kernel"
    
  2. יוצרים סקריפט בשם bind_to_vfio_pci.sh ב-/lib/udev/:

    #!/bin/bash
    
    # Run ./bind_to_vfio_pci.sh <DBDF>
    # Binds the device at <DBDF> to vfio-pci.
    # If the device is already bound to a driver, unbinds it first.
    
    # Load the vfio-pci module into the kernel. No-op if already loaded.
    modprobe vfio-pci
    
    DBDF_REGEX="^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}.[[:xdigit:]]$"
    
    unset BDF
    if [[ $1 =~ $DBDF_REGEX ]]; then
        BDF=$1
    else
        echo "Error: BDF arg ($1) is not in form dddd:bb:dd.f"
        exit 1
    fi
    
    PCI_PATH="/sys/bus/pci/devices/$BDF"
    
    echo "vfio-pci" > "$PCI_PATH/driver_override"
    
    PCI_DRIVER_PATH="$PCI_PATH/driver"
    if [[ -d "$PCI_DRIVER_PATH" ]]; then
        curr_driver=$(readlink "$PCI_DRIVER_PATH")
            curr_driver=${curr_driver##*/}
        if [[ $curr_driver == "vfio-pci" ]]; then
            echo "$BDF already bound to vfio-pci"
            exit 0
        else
            echo "$BDF" > "$PCI_DRIVER_PATH/unbind"
            if [[ -d "$PCI_DRIVER_PATH" ]]; then
                echo "Error: Unable to unbind $PCI_DRIVER_PATH"
                exit 1
            fi
            echo "Unbound $BDF from driver $curr_driver"
        fi
    fi
    echo "$BDF" > /sys/bus/pci/drivers_probe
    echo "Bound $BDF to vfio-pci"
    
    # Grant read/write access on VFIO device to all users
    IOMMU_GROUP=$(readlink "$PCI_PATH/iommu_group" | xargs basename)
    VFIO_DEV="/dev/vfio/$IOMMU_GROUP"
    if [[ -c "$VFIO_DEV" ]]; then
        chmod 0666 "$VFIO_DEV"
    else
        echo "$VFIO_DEV not found"
        exit 1
    fi
    
    # Set allow_unsafe_interrupts for x86 platforms.
    (uname -a | grep -q x86_64) && echo 1 > /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts
    
    # This is only needed to avoid non-zero exit code from previous command.
    echo "All Done!"
    
  3. הופכים את הסקריפט לניתן להפעלה:

    chmod +x /lib/udev/bind_to_vfio_pci.sh
    
  4. נותנים לכל המשתמשים במערכת גישה למכשיר ה-TPU:

    echo 'KERNEL=="accel*" MODE="0666"' >> /etc/udev/rules.d/99-tpu.rules
    

שינוי התמונה כדי לשפר את הביצועים

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

מגבלות זיכרון

כדי לאפשר לתהליך יחיד לנעול זיכרון ללא הגבלה, מעדכנים את /etc/security/limits.conf:

echo '*  hard  memlock  unlimited' >> /etc/security/limits.conf
echo '*  soft  memlock  unlimited' >> /etc/security/limits.conf

מגבלות על קבצים

כדי להגדיל את מספר הקבצים הפתוחים, מעדכנים את /etc/security/limits.conf:

echo "*    soft    nofile       100000" >> /etc/security/limits.conf
echo "*    hard    nofile       100000" >> /etc/security/limits.conf
echo "root soft    nofile       100000" >> /etc/security/limits.conf
echo "root hard    nofile       100000" >> /etc/security/limits.conf

פרמטרים של ליבה (kernel)

מעדכנים את הגדרות ה-GRUB (בדרך כלל ב-/etc/default/grub) כך שיכללו את הפרמטרים הבאים ב-GRUB_CMDLINE_LINUX:

  • ‫idle=poll: מונעת מהמעבד (CPU) להיכנס למצבי חוסר פעילות בצריכת חשמל נמוכה.
  • ‫transparent_hugepage=always: הפעלה של Transparent Huge Pages ‏(THP).
  • ‫iommu.passthrough=0: השבתת מצב מעבר של יחידת ניהול זיכרון קלט-פלט (IOMMU).
  • ‫panic=-1: הגדרת הליבה להפעלה מחדש באופן מיידי אם מתרחשת תגובה לשגיאת ליבה קריטית.
  • ‫intel_iommu=on,sm_on: מפעיל את Intel IOMMU במצב שניתן להתאמה. נדרש לארכיטקטורות TPU7x ו-v5p.

כך מעדכנים את הפרמטרים האלה של הליבה:

  1. מגדירים את המשתנה של שורת הפקודה של הליבה באמצעות הפרמטרים הנפוצים:

    kernel_cmdline="idle=poll transparent_hugepage=always iommu.passthrough=0 panic=-1"
    
  2. אם אתם יוצרים קובץ אימג' ל-TPU7x או ל-TPU v5p, הוסיפו את הפרמטר Intel IOMMU:

    kernel_cmdline="${kernel_cmdline} intel_iommu=on,sm_on"
    
  3. מעדכנים את GRUB_CMDLINE_LINUX ב-/etc/default/grub ויוצרים מחדש את הגדרת ה-GRUB:

    sed -i "s/^GRUB_CMDLINE_LINUX=\".*\"/GRUB_CMDLINE_LINUX=\"${kernel_cmdline}\"/" /etc/default/grub
    echo "Status: New kernel cmdline: $(grep -e '^GRUB_CMDLINE_LINUX=' /etc/default/grub)"
    
    update-grub
    

התקנת סוכן vBar

סוכן vBar נדרש כדי שרשת החיבורים בין השבבים (ICI) תפעל.

כדי לשלוף את קובץ האימג' של קונטיינר הסוכן של vBar במהלך יצירת קובץ האימג', מריצים את הפקודות הבאות:

  1. מאמתים את Docker באמצעות gcr.io:

    gcloud auth configure-docker gcr.io
    
  2. מורידים את קובץ האימג' של Docker של נציג vBar:

    docker pull gcr.io/cloud-tpu-v2-images/vbar_control_agent:0.0.3
    

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

אופציונלי: התקנה והפעלה של AI Telemetry Collector

הכלי AI Telemetry Collector פועל בתוך ה-TPU VM ומאפשר לכם לגשת למדדי זמן ריצה ותשתית דרך Cloud Monitoring או דרך צינור עיבוד הנתונים שלכם למעקב שמבוסס על Prometheus. כדי להשתמש ב-AI Telemetry Collector עם מערכת הפעלה בהתאמה אישית, צריך להשתמש בקובץ האימג' של Docker ב-ai-telemetry-collector. אתם יכולים להתקין את קובץ האימג' במערכת ההפעלה בהתאמה אישית, ולהשתמש בקובץ config.yaml כדי לקבוע את מרווחי הזמן לאיסוף, להפעיל או להשבית מדדים ספציפיים או לשנות את יעדי הייצוא.

כדי להתקין ולהפעיל את AI Telemetry Collector, מריצים את הפקודות הבאות:

  1. מאמתים את Docker באמצעות gcr.io:

    gcloud auth configure-docker gcr.io
    
  2. מורידים את קובץ האימג' של Docker ל-AI Telemetry Collector:

    docker pull gcr.io/cloud-tpu-v2-images/ai-telemetry-collector:latest
    
  3. מריצים קונטיינר באמצעות קובץ האימג' של AI Telemetry Collector עם הגדרת ברירת המחדל:

    docker run -d --restart=always --privileged --net=host gcr.io/cloud-tpu-v2-images/ai-telemetry-collector:latest
    

    במאמר AI Telemetry Collector מוסבר איך להשתמש בקובץ תצורה בהתאמה אישית או להוסיף קובצי תצורה נוספים.

ביצוע שינויים בזמן ההפעלה

מגדירים את קובץ האימג' כך שיבצע את המשימות שבקטעים הבאים בכל פעם ש-VM מופעל. אתם יכולים להשתמש בכלי cloud-init כדי להגדיר משימות בזמן ההפעלה, על ידי העברת מטא-נתונים למכונות. ההגדרות בקטעים הבאים משתמשות במודולים כמו write_files ו-runcmd. קטעי קוד שמגדירים קבצים לכתיבה צריכים להיכלל במפתח write_files:, ופקודות שצריך להריץ בזמן ההפעלה צריכות להיכלל במפתח runcmd: בהגדרות של cloud-init.

הפעלת הסוכן של vBar

מפעילים את מאגר סוכן הבקרה של vBar בזמן האתחול:

docker run -d --restart=always --privileged --net=host \
  -e HOME=/home/tpu-runtime --name=vbar_control_agent \
  gcr.io/cloud-tpu-v2-images/vbar_control_agent:0.0.3 \
  vbar_control_agent_files/bin/vbar_control_agent --logtostderr

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

כדי לוודא שהסביבה שלכם מאותחלת בצורה נכונה לעומסי עבודה של TPU, אתם צריכים לאחזר משתני הגדרה של זמן ריצה משרת המטא-נתונים של Compute Engine במהלך תהליך האתחול של המערכת. כדי לעשות את זה, מוסיפים את קטע הקוד הבא לקטע write_files: של ההגדרה cloud-init, שיוצר סקריפט בשם /var/scripts/configure-env-vars.sh. הסקריפט הזה מאחזר באופן אוטומטי מאפיינים ממפתח המטא-נתונים tpu-env ושומר אותם ב-/home/tpu-runtime/tpu-env, כדי שמחסנית התוכנה של ה-TPU תוכל להשתמש בהם.

write_files:
  - path: /var/scripts/configure-env-vars.sh
    permissions: '0755'
    owner: root
    content: |
      #!/bin/bash
      grep -q CLOUDSDK_PYTHON /etc/environment || echo "CLOUDSDK_PYTHON=/usr/bin/python3" >> /etc/environment
      export HOME=/home/tpu-runtime
      mkdir -p "${HOME}"
      curl -s 'http://metadata.google.internal/computeMetadata/v1/instance/attributes/tpu-env' -H 'Metadata-Flavor: Google' > /tmp/tpu-env.yaml
      python3 -c '
      import yaml
      with open("/tmp/tpu-env.yaml", "r") as stream_in:
        for k, v in (yaml.safe_load(stream_in) or {}).items():
          print("{var}={value}".format(var=k, value=str(v)))
      ' > "${HOME}/tpu-env"
      rm -f /tmp/tpu-env.yaml
      set -a
      source "${HOME}/tpu-env"
      set +a

קבלת מטא-נתונים של מכונות וירטואליות

קטע הקוד הבא יוצר סקריפט בשם /var/scripts/get-vm-metadata.py, כלי Python לשליחת שאילתות באופן פרוגרמטי לשרת המטא-נתונים, כדי לקבל מאפייני מכונה ספציפיים ותגי מטא-נתונים בהתאמה אישית. מוסיפים את הפרטים הבאים לקטע write_files: בהגדרות של cloud-init:

write_files:
  - path: /var/scripts/get-vm-metadata.py
    permissions: '0755'
    owner: root
    content: |
      #!/usr/bin/env python3
      import os
      import sys
      import requests

      if len(sys.argv) < 2:
        sys.stderr.write('Must provide key')
        os._exit(1)

      key = sys.argv[1]
      default = None
      if len(sys.argv) > 2:
        default = sys.argv[2]

      attribute_type = 'attributes'
      if len(sys.argv) > 3:
        attribute_type = sys.argv[3]

      request = requests.get(
          'http://metadata.google.internal/computeMetadata/v1/instance/{}/{}'.format(
              attribute_type, key
          ),
          headers={'Metadata-Flavor': 'Google'},
      )
      if request.status_code == 200:
        print(request.text)
      elif request.status_code in (403, 404):
        sys.stderr.write('Metadata key: {} does not exist\n'.format(key))
        if default:
          print(default)
      else:
        sys.stderr.write('Lookup failed with: {}'.format(request))

הגדלת הזמן הקצוב לתפוגה ב-Cloud Storage

אם עומס העבודה שלכם יוצר אינטראקציה עם Cloud Storage, אתם יכולים להאריך את משך הזמן הקצוב לתפוגה על ידי הוספת ערכי זמן קצוב לתפוגה ל-/etc/environment. כדי לעשות את זה, מוסיפים את קטע הקוד הבא לקטע write_files: בהגדרות של cloud-init, שיוצר סקריפט בשם /var/scripts/configure-gcs-timeouts.sh.

write_files:
  - path: /var/scripts/configure-gcs-timeouts.sh
    permissions: '0755'
    owner: root
    content: |
      #!/bin/bash
      echo "GCS_RESOLVE_REFRESH_SECS=60" >> /etc/environment
      echo "GCS_REQUEST_CONNECTION_TIMEOUT_SECS=300" >> /etc/environment
      echo "GCS_METADATA_REQUEST_TIMEOUT_SECS=300" >> /etc/environment
      echo "GCS_READ_REQUEST_TIMEOUT_SECS=300" >> /etc/environment
      echo "GCS_WRITE_REQUEST_TIMEOUT_SECS=600" >> /etc/environment

קביעת הגדרות הרשת

כדי לשפר את קצב העברת הנתונים ואת זמן האחזור ברשת במכונות וירטואליות של TPU, מוסיפים את הסקריפטים הבאים לקטע write_files: בהגדרות של cloud-init. במכונות וירטואליות מסוג TPU v6e ו-TPU7x, הסקריפטים האלה גם מאפשרים פיצול נתוני TCP, מגדילים את מגבלות מאגר הנתונים (buffer) לקבלת TCP ומפזרים את הפסיקות של ה-NIC בין ליבות NUMA. הסקריפטים האלה דורשים את הסקריפט /var/scripts/get-vm-metadata.py מהקטע קבלת מטא-נתונים של מכונות וירטואליות.

write_files:
  - path: /var/scripts/configure-networking.sh
    permissions: '0755'
    owner: root
    content: |
      #!/bin/bash
      ACCELERATOR_TYPE=$(/usr/bin/python3 /var/scripts/get-vm-metadata.py accelerator-type)
      if [[ "$ACCELERATOR_TYPE" =~ ^v6e ]] || [[ "$ACCELERATOR_TYPE" =~ ^tpu7 ]]; then
        echo "Enabling max rx buffer size for v6e, tpu7x & tpu7"
        for port in $(ls /sys/class/net | grep ens); do
          dhclient -r "$port"
          if ethtool -h | grep -q tcp-data-split; then
            if ethtool -G "$port" tcp-data-split on; then
              echo "Max RX buffer size and TCP data split enabled for $port"
            else
              echo "Unable to enable max RX buffer size and TCP data split for $port"
            fi
          else
            if ethtool --set-priv-flags "$port" enable-max-rx-buffer-size on; then
              echo "Max RX buffer size enabled for $port"
            else
              echo "Unable to enable max RX buffer size for $port"
            fi
          fi
          dhclient "$port"
        done
      else
        echo "Skipping max rx buffer size for TPU generation $ACCELERATOR_TYPE before v6e"
      fi

  - path: /var/scripts/set_tcp_config.sh
    permissions: '0755'
    owner: root
    content: |
      #!/bin/bash
      echo "Setting TCP config"

      # Disable metrics cache
      sysctl -w net.ipv4.tcp_no_metrics_save=1

      # Disable slow start after idle
      sysctl -w net.ipv4.tcp_slow_start_after_idle=0

      # Set rto_min 5ms and enable quickack
      sysctl_rto_min_exists=$(sysctl -a | grep tcp_rto_min_us)
      if [[ -z "$sysctl_rto_min_exists" ]]; then
        ip route show | while IFS= read -r route; do
          if ! echo "$route" | grep -q "linkdown"; then
            ip route change ${route/lock/} rto_min 5ms quickack 1
          fi
        done
      else
        sysctl -w net.ipv4.tcp_rto_min_us=5000
        ip route show | while IFS= read -r route; do
          if ! echo "$route" | grep -q "linkdown"; then
            ip route change ${route/lock/} quickack 1
          fi
        done
      fi

      # Increase TCP zerocopy control memory
      sysctl -w net.core.optmem_max=131072

      # Disable Cubic Hystart Ack-Train
      echo 2 > /sys/module/tcp_cubic/parameters/hystart_detect

      ACCELERATOR_TYPE=$(/usr/bin/python3 /var/scripts/get-vm-metadata.py accelerator-type)
      if [[ "$ACCELERATOR_TYPE" =~ ^v6e ]] || [[ "$ACCELERATOR_TYPE" =~ ^tpu7 ]]; then
        # Increase TCP receive buffer limits
        echo "4096 41943040 314572800" > /proc/sys/net/ipv4/tcp_rmem
      fi

  - path: /var/scripts/spread-nic-irqs.sh
    permissions: '0755'
    owner: root
    content: |
      #!/bin/bash
      ACCELERATOR_TYPE=$(/usr/bin/python3 /var/scripts/get-vm-metadata.py accelerator-type)
      if [[ "$ACCELERATOR_TYPE" == v6e* ]] || [[ "$ACCELERATOR_TYPE" == tpu7* ]]; then
        node0_cores=$(echo /sys/devices/system/node/node0/cpu[0-9]* | wc -w)
        ht_buddies=$(cat /sys/devices/system/cpu/cpu0/topology/core_cpus_list | tr ',' ' ' | wc -w)
        total_schedulable_cores=$((node0_cores / ht_buddies))
        second_numa_starting_core=${total_schedulable_cores}

        first_numa_core=0
        second_numa_core=${second_numa_starting_core}
        for nic in $(ls -1 /sys/class/net); do
          if [[ -d "/sys/class/net/$nic/device" ]]; then
            NUM_QUEUES=$(echo /sys/class/net/"$nic"/queues/tx* | wc -w)
            base_ntfy_block=$(ls -1 /sys/class/net/"${nic}"/device/msi_irqs | sort -n | head -n 1)
            num_ntfy_blocks=$(ls /sys/class/net/"${nic}"/device/msi_irqs/ | wc -w)
            tx_irq_base_directory=$((base_ntfy_block))
            rx_irq_base_directory=$((base_ntfy_block + (num_ntfy_blocks / 2)))

            core=0
            max_core=${total_schedulable_cores}
            nic_numa=$(cat /sys/class/net/"${nic}"/device/numa_node)
            if [[ "${nic_numa}" -eq "1" ]]; then
              core=${second_numa_core}
              max_core=$((second_numa_starting_core + total_schedulable_cores))
            else
              core=${first_numa_core}
            fi

            for ((queue = 0; queue < $NUM_QUEUES; queue++)); do
              echo $core > /proc/irq/$((tx_irq_base_directory + $queue))/smp_affinity_list
              echo $core > /proc/irq/$((rx_irq_base_directory + $queue))/smp_affinity_list
              cp /proc/irq/$((tx_irq_base_directory + $queue))/smp_affinity /sys/class/net/"$nic"/queues/tx-"$queue"/xps_cpus
              core=$((core + 1))
              if [[ $core -ge $max_core ]]; then
                if [[ "${nic_numa}" -eq "1" ]]; then
                  core=${second_numa_starting_core}
                else
                  core=0
                fi
              fi
            done

            if [[ "${nic_numa}" -eq "1" ]]; then
              second_numa_core=${core}
            else
              first_numa_core=${core}
            fi
          fi
        done
      else
        echo "Skipping NIC IRQ spreading for TPU generation $ACCELERATOR_TYPE before v6e"
      fi

מריצים את הסקריפטים של האתחול

כדי להריץ את הסקריפטים של ההגדרות באופן אוטומטי כשהמכונה הווירטואלית מופעלת, מוסיפים את הקטע runcmd: להגדרות של cloud-init:

runcmd:
  - /var/scripts/configure-env-vars.sh
  - /var/scripts/configure-gcs-timeouts.sh
  - /var/scripts/configure-networking.sh
  - /var/scripts/set_tcp_config.sh
  - /var/scripts/spread-nic-irqs.sh

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