Benutzerdefiniertes Betriebssystem-Image verwenden
Sie können ein benutzerdefiniertes Betriebssystem-Image für Ihre TPU-VMs verwenden, um Software vorab zu laden, eine bestimmte Betriebssystemdistribution zu verwenden oder benutzerdefinierte Kernel-Änderungen anzuwenden. Beim Erstellen eines benutzerdefinierten Images müssen während des Image-Erstellungsprozesses bestimmte Systemänderungen vorgenommen und das Image so konfiguriert werden, dass es die für die TPU-Funktionalität erforderlichen Boot-Aufgaben ausführt.
Beachten Sie die folgenden Haftungsausschlüsse, wenn Sie ein benutzerdefiniertes Betriebssystem-Image mit TPUs verwenden:
- Google stellt standardmäßige, TPU-optimierte Ubuntu-Langzeitsupport-Images (LTS) bereit. Die auf dieser Seite aufgeführten Betriebssystemänderungen werden nur für die von Google unterstützten, TPU-optimierten Ubuntu LTS-Images validiert.
- Sie sind dafür verantwortlich, die erforderlichen Betriebssystemänderungen für andere Betriebssystemdistributionen oder benutzerdefinierte Images zu extrapolieren. Google garantiert nicht, dass die auf dieser Seite aufgeführten Änderungen für Ubuntu mit anderen Betriebssystemdistributionen oder einem anderen Ubuntu-Image mit einem benutzerdefinierten Kernel funktionieren.
- Google erstellt und testet keine anderen Betriebssystem-Images als die standardmäßigen TPU-optimierten Ubuntu LTS-Images. Sie müssen Ihr benutzerdefiniertes Betriebssystem-Image erstellen und testen.
Weitere Informationen zu den standardmäßigen TPU-optimierten Ubuntu LTS-Images finden Sie unter TPU-Betriebssystem-Images.
Vorbereitung
Auf dem Basis-Image müssen die folgenden Komponenten installiert sein:
- Docker
ethtool, Version 6.7 oder höher, wenn Sie TPU v6e oder TPU7x verwenden- Python 3 mit den Paketen
PyYAMLundrequests, die in Ubuntu alspython3-yamlundpython3-requestsverfügbar sind - gcloud-CLI
Für TPU7x-VMs muss Ihr Basis-Image mindestens die Linux-Kernel-Version 6.8 des Gastbetriebssystems verwenden.
Änderungen während der Image-Erstellung vornehmen
Wenden Sie die folgenden Änderungen an, während Sie Ihr benutzerdefiniertes Ubuntu-Image erstellen.
Unbeaufsichtigte Upgrades deaktivieren
Deaktivieren und entfernen Sie unattended-upgrades, damit Paketaktualisierungen im Hintergrund die dpkg-Sperre nicht halten oder TPU-Arbeitslasten unterbrechen:
echo 'APT::Periodic::Unattended-Upgrade "0";' > /etc/apt/apt.conf.d/99cloudtpuconf
DEBIAN_FRONTEND=noninteractive apt-get -y purge unattended-upgrades
TPU-Geräte an VFIO binden
Damit das Gastbetriebssystem auf die TPU-Hardware zugreifen kann, müssen Sie TPU-Geräte an den vfio-pci-Treiber binden.
Erstellen Sie in
/etc/udev/rules.d/eine udev-Regeldatei mit dem Namen99-tpu-vfiopci.rules:# 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"Erstellen Sie in
/lib/udev/ein Script mit dem Namenbind_to_vfio_pci.sh:#!/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!"Machen Sie das Skript ausführbar:
chmod +x /lib/udev/bind_to_vfio_pci.shGewähren Sie allen Nutzern im System Zugriff auf das TPU-Gerät:
echo 'KERNEL=="accel*" MODE="0666"' >> /etc/udev/rules.d/99-tpu.rules
Bild optimieren, um die Leistung zu verbessern
Passen Sie die folgenden Systemlimits und Parameter an, um eine optimale Leistung zu erzielen.
Beschränkungen des Arbeitsspeichers
Aktualisieren Sie /etc/security/limits.conf, um einem einzelnen Prozess zu erlauben, unbegrenzten Arbeitsspeicher zu sperren:
echo '* hard memlock unlimited' >> /etc/security/limits.conf
echo '* soft memlock unlimited' >> /etc/security/limits.conf
Dateilimits
Erhöhen Sie die Anzahl der geöffneten Dateien, indem Sie /etc/security/limits.conf aktualisieren:
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-Parameter
Aktualisieren Sie Ihre GRUB-Konfiguration (normalerweise in /etc/default/grub), um die folgenden Parameter in GRUB_CMDLINE_LINUX einzufügen:
idle=poll: Verhindert, dass die CPU in den Energiesparmodus wechselt.transparent_hugepage=always: Aktiviert Transparent Huge Pages (THP).iommu.passthrough=0: Deaktiviert den Passthrough-Modus der Input-Output Speicherverwaltungseinheit (IOMMU).panic=-1: Konfiguriert den Kernel so, dass er sofort neu gestartet wird, wenn eine Kernel-Panic auftritt.intel_iommu=on,sm_on: Aktiviert Intel IOMMU im skalierbaren Modus. Erforderlich für TPU7x- und v5p-Architekturen.
In den folgenden Schritten wird beschrieben, wie Sie diese Kernelparameter aktualisieren:
Legen Sie die Kernel-Befehlszeilenvariable mit den allgemeinen Parametern fest:
kernel_cmdline="idle=poll transparent_hugepage=always iommu.passthrough=0 panic=-1"Wenn Sie ein Image für TPU7x oder TPU v5p erstellen, hängen Sie den Intel-IOMMU-Parameter an:
kernel_cmdline="${kernel_cmdline} intel_iommu=on,sm_on"Aktualisieren Sie
GRUB_CMDLINE_LINUXin/etc/default/grubund generieren Sie die GRUB-Konfiguration neu: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-Agent installieren
Der vBar-Agent ist erforderlich, damit das ICI-Netzwerk (Inter-Chip Interconnect) funktioniert.
Führen Sie die folgenden Befehle aus, um das vBar-Agent-Container-Image während der Image-Erstellung abzurufen:
Authentifizieren Sie Docker mit
gcr.io:gcloud auth configure-docker gcr.ioRufen Sie das Docker-Image des vBar-Agents ab:
docker pull gcr.io/cloud-tpu-v2-images/vbar_control_agent:0.0.3
Informationen zum Konfigurieren des Images, um den vBar-Agent-Container beim Booten zu starten, finden Sie unter vBar-Agent starten.
Optional: AI Telemetry Collector installieren und ausführen
Der AI Telemetry Collector wird in der TPU-VM ausgeführt und ermöglicht Ihnen den Zugriff auf Laufzeit- und Infrastrukturmesswerte über Cloud Monitoring oder über Ihre eigene Prometheus-basierte Monitoring-Pipeline. Sie können den AI Telemetry Collector mit einem benutzerdefinierten Betriebssystem verwenden, indem Sie das Docker-Image ai-telemetry-collector verwenden. Sie können das Image auf Ihrem benutzerdefinierten Betriebssystem installieren und mit einer config.yaml-Datei die Erfassungsintervalle festlegen, bestimmte Messwerte aktivieren oder deaktivieren oder die Exportziele ändern.
Führen Sie die folgenden Befehle aus, um den AI Telemetry Collector zu installieren und auszuführen:
Authentifizieren Sie Docker mit
gcr.io:gcloud auth configure-docker gcr.ioRufen Sie das Docker-Image für den AI Telemetry Collector ab:
docker pull gcr.io/cloud-tpu-v2-images/ai-telemetry-collector:latestFühren Sie einen Container mit dem AI Telemetry Collector-Image und der Standardkonfiguration aus:
docker run -d --restart=always --privileged --net=host gcr.io/cloud-tpu-v2-images/ai-telemetry-collector:latestInformationen zur Verwendung einer benutzerdefinierten Konfigurationsdatei oder zum Hinzufügen zusätzlicher Konfigurationsdateien finden Sie unter AI Telemetry Collector.
Änderungen an der Startzeit vornehmen
Konfigurieren Sie Ihr Image so, dass die Aufgaben in den folgenden Abschnitten bei jedem Start einer VM ausgeführt werden. Mit dem Tool cloud-init können Sie Aufgaben für die Bootzeit konfigurieren, indem Sie Metadaten an Ihre Instanzen übergeben. In den Konfigurationen in den folgenden Abschnitten werden Module wie write_files und runcmd verwendet.
Snippets, die zu schreibende Dateien definieren, sollten unter dem Schlüssel write_files: und Befehle, die beim Booten ausgeführt werden sollen, unter dem Schlüssel runcmd: in Ihrer cloud-init-Konfiguration enthalten sein.
vBar-Agent starten
Starten Sie den vBar-Steuerungs-Agent-Container beim Booten:
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
Umgebungsvariablen konfigurieren
Damit Ihre Umgebung für TPU-Arbeitslasten richtig initialisiert wird, müssen Sie während des Systemstartvorgangs Laufzeitkonfigurationsvariablen vom Compute Engine-Metadatenserver abrufen. Fügen Sie dazu das folgende Snippet in den Abschnitt write_files: Ihrer cloud-init-Konfiguration ein, wodurch ein Script mit dem Namen /var/scripts/configure-env-vars.sh erstellt wird. Dieses Skript automatisiert das Abrufen von Attributen aus dem Metadatenschlüssel tpu-env und speichert sie in /home/tpu-runtime/tpu-env, damit sie vom TPU-Software-Stack verwendet werden können.
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
VM-Metadaten abrufen
Mit dem folgenden Snippet wird ein Script namens /var/scripts/get-vm-metadata.py erstellt. Dabei handelt es sich um ein Python-Dienstprogramm, mit dem der Metadatenserver programmatisch nach bestimmten Instanzattributen und benutzerdefinierten Metadaten-Tags abgefragt werden kann. Fügen Sie dem Abschnitt write_files: Ihrer cloud-init-Konfiguration Folgendes hinzu:
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-Zeitlimits erhöhen
Wenn Ihre Arbeitslast mit Cloud Storage interagiert, erhöhen Sie die Zeitlimits, indem Sie /etc/environment Zeitlimitwerte hinzufügen. Fügen Sie dazu das folgende Snippet im Abschnitt write_files: Ihrer cloud-init-Konfiguration hinzu. Dadurch wird ein Skript mit dem Namen /var/scripts/configure-gcs-timeouts.sh erstellt.
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
die Netzwerkeinstellungen zu konfigurieren.
Wenn Sie den Netzwerkdurchsatz und die Latenz auf TPU-VMs optimieren möchten, fügen Sie dem Abschnitt write_files: Ihrer cloud-init-Konfiguration die folgenden Skripts hinzu. Auf TPU v6e- und TPU7x-VMs ermöglichen diese Skripts auch die TCP-Datenaufteilung, höhere Limits für den TCP-Empfangspuffer und die Verteilung von NIC-Interrupts auf NUMA-Kerne. Diese Skripts erfordern das Skript /var/scripts/get-vm-metadata.py aus dem Abschnitt VM-Metadaten abrufen.
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
Boot-Scripts ausführen
Wenn die Konfigurationsskripts beim Booten der VM automatisch ausgeführt werden sollen, fügen Sie Ihrer cloud-init-Konfiguration einen runcmd:-Abschnitt hinzu:
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
Nächste Schritte
- TPU-VM-Instanz mit Ihrem benutzerdefinierten Image erstellen
- Sehen Sie sich die verfügbaren TPU-Betriebssystem-Images an.
- TPU-VMs verwalten