|
| 1 | +<!-- |
| 2 | + Copyright 2023–2026 Google LLC |
| 3 | +
|
| 4 | + Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + you may not use this file except in compliance with the License. |
| 6 | + You may obtain a copy of the License at |
| 7 | +
|
| 8 | + https://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | + Unless required by applicable law or agreed to in writing, software |
| 11 | + distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + See the License for the specific language governing permissions and |
| 14 | + limitations under the License. |
| 15 | +--> |
| 16 | + |
| 17 | +(run-cluster-toolkit)= |
| 18 | + |
| 19 | +# At scale with Cluster Toolkit (`gcluster`) |
| 20 | + |
| 21 | +This guide provides the recommended workflow for running MaxText on Google Kubernetes Engine (GKE) using **Cluster Toolkit's `gcluster` CLI**. For a complete reference on Cluster Toolkit and `gcluster`, please see the [official Cluster Toolkit repository](https://github.com/GoogleCloudPlatform/cluster-toolkit) and [Google Cloud documentation](https://cloud.google.com/cluster-toolkit/docs/overview). |
| 22 | + |
| 23 | +## Overview of the workflow |
| 24 | + |
| 25 | +The process involves two main stages: |
| 26 | + |
| 27 | +1. **Packaging or Layering the MaxText Application:** You can either prebuild a MaxText Docker image or use `gcluster`'s built-in Crane integration (`--build-context .`) to automatically build and layer your local MaxText working directory on top of a base image on-the-fly. |
| 28 | +2. **Orchestrating Workload Deployment:** `gcluster job submit` automatically discovers your GKE cluster's accelerator topology, verifies Kueue and JobSet health, generates the required Kubernetes resources (`JobSet`, `ClusterQueue`, `LocalQueue`, `ResourceFlavor`), and deploys your multi-host JAX workload. |
| 29 | + |
| 30 | +```none |
| 31 | ++--------------------------+ +--------------------+ +-------------------+ |
| 32 | +| | | | | | |
| 33 | +| Your Development Machine +------> Artifact Registry +------> GKE Cluster | |
| 34 | +| (with gcluster CLI) | | (Stores your image)| |(with Accelerators)| |
| 35 | +| | | | | | |
| 36 | +| 1. Local MaxText Code | | 2. gcluster builds | | 3. gcluster runs | |
| 37 | +| (--build-context .) | | & pushes image | | multi-host job | |
| 38 | ++--------------------------+ +--------------------+ +-------------------+ |
| 39 | +``` |
| 40 | + |
| 41 | +______________________________________________________________________ |
| 42 | + |
| 43 | +## 1. Prerequisites |
| 44 | + |
| 45 | +Before you begin, ensure you have the necessary client tools installed and permissions configured. |
| 46 | + |
| 47 | +### Required tools |
| 48 | + |
| 49 | +- **Python >= 3.12** with `pip` and `venv`. |
| 50 | +- **Google Cloud CLI (`gcloud`):** Install it from [here](https://cloud.google.com/sdk/docs/install) and run `gcloud init`. |
| 51 | +- **kubectl & GKE auth plugin:** Required for communicating with GKE clusters: |
| 52 | + ```bash |
| 53 | + gcloud components install kubectl gke-gcloud-auth-plugin |
| 54 | + ``` |
| 55 | +- **gcluster CLI:** Follow the official [Cluster Toolkit CLI Installation Guide](https://cloud.google.com/cluster-toolkit/docs/install-cli) (or download the binary from the [releases page](https://github.com/GoogleCloudPlatform/cluster-toolkit/releases)) and ensure `gcluster` is in your `$PATH`. |
| 56 | +- **Docker Credentials:** Configure Docker authentication for your target Artifact Registry region: |
| 57 | + ```bash |
| 58 | + gcloud auth configure-docker <region>-docker.pkg.dev --quiet |
| 59 | + ``` |
| 60 | + |
| 61 | +### GCP permissions and APIs |
| 62 | + |
| 63 | +Make sure the required Google Cloud APIs are enabled on your project: |
| 64 | + |
| 65 | +```bash |
| 66 | +gcloud services enable \ |
| 67 | + container.googleapis.com \ |
| 68 | + artifactregistry.googleapis.com \ |
| 69 | + storage.googleapis.com |
| 70 | +``` |
| 71 | + |
| 72 | +Your Google Cloud user account needs the following IAM roles in your target project: |
| 73 | + |
| 74 | +- Artifact Registry Writer |
| 75 | +- Kubernetes Engine Admin / Developer |
| 76 | +- Storage Admin (for accessing GCS buckets for checkpoints and datasets) |
| 77 | +- Logging / Monitoring Viewer |
| 78 | + |
| 79 | +______________________________________________________________________ |
| 80 | + |
| 81 | +## 2. One-time environment setup |
| 82 | + |
| 83 | +First, ensure your local `kubectl` is authenticated with your target GKE cluster: |
| 84 | + |
| 85 | +```bash |
| 86 | +gcloud container clusters get-credentials <GKE_CLUSTER_NAME> \ |
| 87 | + --region <GCP_REGION_OR_ZONE> \ |
| 88 | + --project <GCP_PROJECT_ID> |
| 89 | +``` |
| 90 | + |
| 91 | +Next, configure your default Google Cloud project, target GKE cluster name, and cluster location in `gcluster`: |
| 92 | + |
| 93 | +```bash |
| 94 | +gcluster job config set project <GCP_PROJECT_ID> |
| 95 | +gcluster job config set cluster <GKE_CLUSTER_NAME> |
| 96 | +gcluster job config set location <GCP_REGION_OR_ZONE> # e.g., europe-west4 or us-east5-a |
| 97 | +``` |
| 98 | + |
| 99 | +When `gcluster` runs, it inspects your GKE cluster and verifies that **Kueue** and **JobSet** custom resource definitions and webhooks are healthy. If Kueue is missing on your cluster, `gcluster` can prompt to install it automatically. |
| 100 | + |
| 101 | +______________________________________________________________________ |
| 102 | + |
| 103 | +## 3. Step-by-Step MaxText TPU Smoke Test (Multi-Host) |
| 104 | + |
| 105 | +To verify that your GKE cluster, Kueue admission queues, and multi-host JAX ICI interconnects are fully functional before launching large production runs, you can run a lightweight synthetic smoke test using MaxText's `default` dummy model (`model_name=default`). |
| 106 | + |
| 107 | +```bash |
| 108 | +cd /path/to/maxtext |
| 109 | + |
| 110 | +gcluster job submit \ |
| 111 | + --base-image us-east5-docker.pkg.dev/cloud-tpu-multipod-dev/maxtext-images/maxtext_base:latest \ |
| 112 | + --build-context . \ |
| 113 | + --command "python3 -m maxtext.trainers.pre_train.train run_name=maxtext-multihost-smoke-test steps=5 dataset_type=synthetic model_name=default enable_checkpointing=False" \ |
| 114 | + --name maxtext-multihost-smoke-test \ |
| 115 | + --compute-type ct5p-hightpu-4t \ |
| 116 | + --topology 4x4x4 |
| 117 | +``` |
| 118 | + |
| 119 | +______________________________________________________________________ |
| 120 | + |
| 121 | +## 4. Run a production MaxText job on GCS datasets |
| 122 | + |
| 123 | +This section assumes you have an existing GKE cluster with TPU or GPU node pools. |
| 124 | + |
| 125 | +### Step 1: Export target image repository |
| 126 | + |
| 127 | +Specify which Artifact Registry repository in your target project and region should store the container image built by `gcluster`. If you do not already have a Docker repository in Artifact Registry, create one: |
| 128 | + |
| 129 | +```bash |
| 130 | +gcloud artifacts repositories create maxtext-images \ |
| 131 | + --repository-format=docker \ |
| 132 | + --location=<GCP_REGION> \ |
| 133 | + --description="MaxText container images" |
| 134 | +``` |
| 135 | + |
| 136 | +For more details, see the official [Artifact Registry documentation](https://cloud.google.com/artifact-registry/docs/docker/store-docker-container-images). Once created, export the repository name: |
| 137 | + |
| 138 | +```bash |
| 139 | +export GCLUSTER_IMAGE_REPO=maxtext-images |
| 140 | +``` |
| 141 | + |
| 142 | +### Step 2: Submit a training workload |
| 143 | + |
| 144 | +Navigate to the root directory of your local MaxText repository and submit the job using `gcluster job submit`. |
| 145 | + |
| 146 | +Passing `--build-context .` packages your local MaxText source directory on top of a lightweight base image (`--base-image`) and builds/pushes the container image on-the-fly. This allows you to test local code modifications rapidly without manually building a Docker container image. |
| 147 | + |
| 148 | +*(Note: If you already have a fully pre-built custom container image containing your code pushed to Artifact Registry, you can specify `--image <FULL_IMAGE_URI>` directly instead of `--base-image` and `--build-context`.)* |
| 149 | + |
| 150 | +```bash |
| 151 | +cd /path/to/maxtext |
| 152 | + |
| 153 | +gcluster job submit \ |
| 154 | + --base-image us-east5-docker.pkg.dev/cloud-tpu-multipod-dev/maxtext-images/maxtext_base:latest \ |
| 155 | + --build-context . \ |
| 156 | + --command "python3 -m maxtext.trainers.pre_train.train run_name=maxtext-test base_output_directory=gs://<MY_BUCKET>/output dataset_path=gs://<MY_DATASET>/ steps=100" \ |
| 157 | + --name maxtext-test \ |
| 158 | + --compute-type ct5p-hightpu-4t \ |
| 159 | + --topology 4x4x4 |
| 160 | +``` |
| 161 | + |
| 162 | +#### Key Flags: |
| 163 | + |
| 164 | +- `--compute-type`: The accelerator machine flavor or accelerator type (e.g., `ct5p-hightpu-4t` for TPU v5p, or `ct6e-hightpu-4t` for TPU v6e). |
| 165 | +- `--topology`: The physical 3D mesh topology required for multi-host TPU slices (e.g., `4x4x4` allocates 64 chips across 16 physical nodes; `2x2x1` allocates 4 chips on 1 node). |
| 166 | +- `--build-context`: Path to your local build directory (`.`), allowing rapid iterative testing of local MaxText changes. |
| 167 | + |
| 168 | +______________________________________________________________________ |
| 169 | + |
| 170 | +## 5. Running with Ahead-of-Time (AOT) Compilation |
| 171 | + |
| 172 | +Ahead-of-Time (AOT) compilation can significantly reduce the startup time of your training job by pre-compiling the JAX training step for a specific hardware topology. With `gcluster`, you can generate the compiled pickle locally and include it via `--build-context .`. |
| 173 | + |
| 174 | +### Step 1: Generate the AOT artifact |
| 175 | + |
| 176 | +Note that running `train_compile.py` locally requires a Python environment with MaxText and JAX installed. Follow the [MaxText Getting Started Guide](https://github.com/AI-Hypercomputer/maxtext#getting-started) to set up your local environment before running compilation. |
| 177 | + |
| 178 | +Run `train_compile.py` locally to create the compiled artifact for the target TPU topology: |
| 179 | + |
| 180 | +```bash |
| 181 | +export TPU_TYPE="your-tpu-type" # e.g. "v5p-128" |
| 182 | +export NUM_SLICES=1 |
| 183 | +export PER_DEVICE_BATCH_SIZE=1 |
| 184 | + |
| 185 | +python3 -m maxtext.trainers.pre_train.train_compile \ |
| 186 | + compile_topology=${TPU_TYPE} \ |
| 187 | + compile_topology_num_slices=${NUM_SLICES} \ |
| 188 | + compiled_trainstep_file=maxtext_${TPU_TYPE}_aot.pickle \ |
| 189 | + per_device_batch_size=${PER_DEVICE_BATCH_SIZE} |
| 190 | +``` |
| 191 | + |
| 192 | +This creates `maxtext_${TPU_TYPE}_aot.pickle` in your MaxText repository root directory. |
| 193 | + |
| 194 | +### Step 2: Submit the workload referencing the AOT artifact |
| 195 | + |
| 196 | +When you run `gcluster job submit` with `--build-context .`, the generated pickle file is automatically packaged into the container image. Pass `compiled_trainstep_file=maxtext_${TPU_TYPE}_aot.pickle` to tell MaxText to load the pre-compiled step: |
| 197 | + |
| 198 | +```bash |
| 199 | +gcluster job submit \ |
| 200 | + --base-image us-east5-docker.pkg.dev/cloud-tpu-multipod-dev/maxtext-images/maxtext_base:latest \ |
| 201 | + --build-context . \ |
| 202 | + --command "python3 -m maxtext.trainers.pre_train.train run_name=maxtext-aot-test base_output_directory=gs://<MY_BUCKET>/output dataset_path=gs://<MY_DATASET>/ steps=100 per_device_batch_size=1 compiled_trainstep_file=maxtext_${TPU_TYPE}_aot.pickle" \ |
| 203 | + --name maxtext-aot-test \ |
| 204 | + --compute-type ct5p-hightpu-4t \ |
| 205 | + --topology 4x4x4 |
| 206 | +``` |
| 207 | + |
| 208 | +______________________________________________________________________ |
| 209 | + |
| 210 | +## 6. Monitoring and managing workloads |
| 211 | + |
| 212 | +### List Jobs on the Cluster |
| 213 | + |
| 214 | +View active or queued workloads in the cluster: |
| 215 | + |
| 216 | +```bash |
| 217 | +gcluster job list |
| 218 | +``` |
| 219 | + |
| 220 | +### Check Pod Status |
| 221 | + |
| 222 | +List all pods belonging to your submitted workload: |
| 223 | + |
| 224 | +```bash |
| 225 | +kubectl get pods -l gcluster.google.com/workload=<JOB_NAME> |
| 226 | +``` |
| 227 | + |
| 228 | +### View Workload Logs |
| 229 | + |
| 230 | +Stream logs from the leader container using `gcluster` or `kubectl`: |
| 231 | + |
| 232 | +```bash |
| 233 | +gcluster job logs <JOB_NAME> |
| 234 | +# Or using kubectl: |
| 235 | +kubectl logs -f -l gcluster.google.com/workload=<JOB_NAME>,jobset.sigs.k8s.io/job-index=0 |
| 236 | +``` |
| 237 | + |
| 238 | +Or use the Google Cloud Console Logs Explorer link printed by `gcluster job submit`. |
| 239 | + |
| 240 | +### Cancel or Delete a Job |
| 241 | + |
| 242 | +To terminate a running workload or clean up completed JobSet resources: |
| 243 | + |
| 244 | +```bash |
| 245 | +gcluster job cancel <JOB_NAME> |
| 246 | +``` |
| 247 | + |
| 248 | +Or delete the Kubernetes JobSet directly: |
| 249 | + |
| 250 | +```bash |
| 251 | +kubectl delete jobset <JOB_NAME> |
| 252 | +``` |
0 commit comments