2929#
3030# Usage:
3131# bash src/maxtext/trainers/post_train/distillation/scripts/run_distill_xpk.sh prep_image # one-time image layering
32+ # bash src/maxtext/trainers/post_train/distillation/scripts/run_distill_xpk.sh upload_runner # bake workspace + push to GCR
3233# bash src/maxtext/trainers/post_train/distillation/scripts/run_distill_xpk.sh submit # fire-and-forget; returns in ~60s
3334# bash src/maxtext/trainers/post_train/distillation/scripts/run_distill_xpk.sh monitor # stream logs for the last submit
3435# bash src/maxtext/trainers/post_train/distillation/scripts/run_distill_xpk.sh resume_until_done # auto-retry loop for long jobs
102103# default: git+https://github.com/google/tunix@110932a8395086511228483312131841521695c1
103104# Use "google-tunix==<ver>" once a pypi release ships with the
104105# multi-host shard_input fix.
105- # JAX_PIN default: 0.9.2 — version to pin back after tunix deps resolve.
106- # JAXLIB_PIN default: 0.9.2
107- # LIBTPU_PIN default: 0.0.37
106+ # JAX_PIN default: 0.10.0 — version to pin back after tunix deps resolve.
107+ # Must be ≥ 0.10.0 (tunix's flax dep imports jax.extend.core.Effect).
108+ # JAXLIB_PIN default: 0.10.0
109+ # LIBTPU_PIN default: 0.0.39
110+ #
111+ # upload_runner env vars:
112+ # XPK_RUNNER_IMAGE_NAME default: maxtext_base_image — GCR short name.
113+ # XPK_RUNNER_IMAGE_TAG default: ${USER}-distill — per-user tag avoids
114+ # clobbering shared :latest. Override (or set USER) if
115+ # your shell $USER produces an awkward tag, e.g.
116+ # XPK_RUNNER_IMAGE_TAG=agagik-distill. Pushes to
117+ # gcr.io/$XPK_PROJECT/$XPK_RUNNER_IMAGE_NAME:$XPK_RUNNER_IMAGE_TAG.
108118#
109119# Resume on failure:
110120# `resume_until_done` reuses the same XPK_BASE_OUTPUT_DIR/XPK_WORKLOAD across
@@ -149,9 +159,9 @@ require_env() {
149159
150160# Image pinning (used by prep_image).
151161: " ${TUNIX_SOURCE:= git+https:// github.com/ google/ tunix@ 110932a8395086511228483312131841521695c1} "
152- : " ${JAX_PIN:= 0.9.2 } "
153- : " ${JAXLIB_PIN:= 0.9.2 } "
154- : " ${LIBTPU_PIN:= 0.0.37 } "
162+ : " ${JAX_PIN:= 0.10.0 } "
163+ : " ${JAXLIB_PIN:= 0.10.0 } "
164+ : " ${LIBTPU_PIN:= 0.0.39 } "
155165
156166# Computed at top-level so both submit_workload and resume_until_done can read it.
157167# `${:-}` keeps `set -u` happy for `prep_image`, which doesn't need XPK_BASE_OUTPUT_DIR.
@@ -225,6 +235,31 @@ print(f'tunix {tunix.__version__}: shard_input fix present.')
225235"
226236}
227237
238+ # -------------------------- upload_runner --------------------------
239+ # Bakes ./src into the layered image and pushes to
240+ # gcr.io/$XPK_PROJECT/$XPK_RUNNER_IMAGE_NAME:$XPK_RUNNER_IMAGE_TAG.
241+ # Does the build/tag/push inline rather than calling docker_upload_runner.sh,
242+ # because that script hardcodes :latest and would clobber the shared tag.
243+ upload_runner () {
244+ : " ${XPK_RUNNER_IMAGE_NAME:= maxtext_base_image} "
245+ : " ${XPK_RUNNER_IMAGE_TAG:= ${USER} -distill} "
246+ local target=" gcr.io/${XPK_PROJECT} /${XPK_RUNNER_IMAGE_NAME} :${XPK_RUNNER_IMAGE_TAG} "
247+ echo " == upload_runner -> ${target} =="
248+ if ! sudo docker image inspect " $XPK_BASE_IMAGE " > /dev/null 2>&1 ; then
249+ echo " ERROR: base image $XPK_BASE_IMAGE not found locally. Run prep_image first." >&2
250+ exit 1
251+ fi
252+ local runner_local=" ${XPK_BASE_IMAGE} __runner"
253+ sudo docker build --no-cache \
254+ --build-arg " BASEIMAGE=${XPK_BASE_IMAGE} " \
255+ --build-arg " PACKAGE_DIR=src" \
256+ -f src/dependencies/dockerfiles/maxtext_runner.Dockerfile \
257+ -t " $runner_local " .
258+ sudo docker tag " $runner_local " " $target "
259+ sudo docker push " $target "
260+ echo " Pushed: $target "
261+ }
262+
228263# -------------------------- submit --------------------------
229264submit_workload () {
230265 echo " Workload: $XPK_WORKLOAD "
@@ -243,6 +278,7 @@ submit_workload() {
243278 fi
244279 echo " Image flag: $image_flag =$XPK_BASE_IMAGE "
245280
281+ # PYTHONPATH covers both image flows: /deps/src (upload_runner-baked) and /app/src (xpk crane overlay).
246282 xpk workload create \
247283 --cluster " $XPK_CLUSTER " \
248284 --workload " $XPK_WORKLOAD " \
@@ -252,7 +288,7 @@ submit_workload() {
252288 --project=" $XPK_PROJECT " \
253289 --zone=" $XPK_ZONE " \
254290 " $image_flag =$XPK_BASE_IMAGE " \
255- --command " export PYTHONPATH=/app/src; \
291+ --command " export PYTHONPATH=/deps/src:/ app/src; \
256292export BASE_OUTPUT_DIRECTORY=${OUTPUT_DIR} ; \
257293${gcsfuse_prelude} \
258294python3 -m maxtext.trainers.post_train.distillation.train_distill ${XPK_DISTILL_CONFIG} \
@@ -361,6 +397,10 @@ case "$MODE" in
361397 prep_image)
362398 prep_image
363399 ;;
400+ upload_runner)
401+ require_env XPK_PROJECT # GCR target; default gcloud project is usually wrong here.
402+ upload_runner
403+ ;;
364404 submit|monitor|resume_until_done)
365405 require_env XPK_CLUSTER XPK_PROJECT XPK_ZONE XPK_DEVICE_TYPE XPK_BASE_OUTPUT_DIR
366406 case " $MODE " in
@@ -370,7 +410,7 @@ case "$MODE" in
370410 esac
371411 ;;
372412 * )
373- echo " Unknown mode: $MODE (use prep_image|submit|monitor|resume_until_done)" >&2
413+ echo " Unknown mode: $MODE (use prep_image|upload_runner| submit|monitor|resume_until_done)" >&2
374414 exit 1
375415 ;;
376416esac
0 commit comments