Skip to content

Add A4X MAX Kimi-K2 FP8mx 256 GPUs recipe - #279

Open
ngu3 wants to merge 1 commit into
mainfrom
publish-ninggu-ubench-jktt6qss
Open

Add A4X MAX Kimi-K2 FP8mx 256 GPUs recipe#279
ngu3 wants to merge 1 commit into
mainfrom
publish-ninggu-ubench-jktt6qss

Conversation

@ngu3

@ngu3 ngu3 commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Add A4X MAX Kimi-K2 256 GPUs FP8mx recipe

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a Helm chart recipe to run a kimi-k2 pretraining workload on a4x-max GKE Node pools using the Nvidia Megatron-Bridge framework. The review feedback highlights several critical areas for improvement: hardcoded namespaces and Hugging Face tokens should be parameterized; runtime package installations and git cloning should be moved to a pre-built container image to avoid fragility and rate-limiting; Helm templates should handle null GCS mounts gracefully; and shell/Python scripting in the launcher should be optimized for robustness and memory efficiency.

config_overrides="${config_overrides[*]}"
}

config_overrides=()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The script does not enable set -eo pipefail. Without this, any failures in the torchrun pipeline or other commands will be silently ignored, and the script will exit with status 0 (success), masking critical training crashes from Kubernetes. Enable set -eo pipefail at the start of the script.

Suggested change
config_overrides=()
set -eo pipefail
config_overrides=()

echo "VERSION_DIAGNOSTICS: ${kv}"


export HF_TOKEN=<YOUR_HF_TOKEN>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The hardcoded export HF_TOKEN=<YOUR_HF_TOKEN> in the launcher script overrides any Hugging Face token passed via container environment variables with the literal string <YOUR_HF_TOKEN>. This will cause authentication failures when downloading models or tokenizers. Use the existing environment variable if available.

Suggested change
export HF_TOKEN=<YOUR_HF_TOKEN>
export HF_TOKEN="${HF_TOKEN:-}"

kind: JobSet
metadata:
name: "{{ .Release.Name }}"
namespace: default

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The namespace of the JobSet is hardcoded to default. If the Helm chart is installed in a different namespace, the JobSet will be created in the default namespace while other resources (like ConfigMaps and Services) are created in the target namespace, causing the deployment to fail. Use {{ .Release.Namespace }} instead.

  namespace: "{{ .Release.Namespace }}"

Comment on lines +242 to +250
value: "{{.Release.Name}}-workload-0-0.{{.Release.Name}}.default.svc.cluster.local"
- name: HOSTNAME_PREFIX
value: "{{.Release.Name}}-workload-"
- name: DOMAIN_NAME
value: "{{.Release.Name}}.default.svc.cluster.local"
- name: MASTER_ADDR
value: "{{.Release.Name}}-workload-0-0.{{.Release.Name}}.default.svc.cluster.local"
- name: MASTER_PORT
value: "6002"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The namespace default is hardcoded in RANK_0_FQDN, DOMAIN_NAME, and MASTER_ADDR. If this Helm chart is installed in any namespace other than default, the pods will fail to resolve the master address and the training job will fail to initialize. Use {{ .Release.Namespace }} instead of hardcoding default.

              - name: RANK_0_FQDN
                value: "{{.Release.Name}}-workload-0-0.{{.Release.Name}}.{{.Release.Namespace}}.svc.cluster.local"
              - name: HOSTNAME_PREFIX
                value: "{{.Release.Name}}-workload-"
              - name: DOMAIN_NAME
                value: "{{.Release.Name}}.{{.Release.Namespace}}.svc.cluster.local"
              - name: MASTER_ADDR
                value: "{{.Release.Name}}-workload-0-0.{{.Release.Name}}.{{.Release.Namespace}}.svc.cluster.local"
              - name: MASTER_PORT

Comment on lines +297 to +318
# Install DOCA-OFED
apt update -y
apt install -y curl
export DOCA_URL="https://linux.mellanox.com/public/repo/doca/3.1.0/ubuntu22.04/arm64-sbsa/"
BASE_URL=$([ "${DOCA_PREPUBLISH:-false}" = "true" ] && echo https://doca-repo-prod.nvidia.com/public/repo/doca || echo https://linux.mellanox.com/public/repo/doca)
DOCA_SUFFIX=${DOCA_URL#*public/repo/doca/}; DOCA_URL="$BASE_URL/$DOCA_SUFFIX"
curl $BASE_URL/GPG-KEY-Mellanox.pub | gpg --dearmor > /etc/apt/trusted.gpg.d/GPG-KEY-Mellanox.pub
echo "deb [signed-by=/etc/apt/trusted.gpg.d/GPG-KEY-Mellanox.pub] $DOCA_URL ./" > /etc/apt/sources.list.d/doca.list
apt update
apt install -y --allow-downgrades --allow-change-held-packages -o Dpkg::Options::="--force-overwrite" doca-ofed-userspace || apt --fix-broken install -y

# Install NCCL and nccl-gib-plugins package
apt install --only-upgrade --allow-change-held-packages -y libnccl2 libnccl-dev

# If image not from Google, trust the GCP signing key
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/cloud.google.gpg

# Add gpudirect-gib-apt repo
echo 'deb https://packages.cloud.google.com/apt gpudirect-gib-apt main' | tee /etc/apt/sources.list.d/nccl-gib.list

apt update
apt install -y nccl-gib-plugins

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Performing system-level package installations (apt update, doca-ofed-userspace, libnccl2, nccl-gib-plugins) at runtime on all 64 nodes simultaneously is highly inefficient and fragile. It significantly delays job startup, requires public internet access on all nodes (which fails in private clusters), and is highly susceptible to transient network failures or rate-limiting from external package repositories. These dependencies should be pre-installed in a custom Docker image instead.

Comment on lines +98 to +103
cd /opt
rm -rf Megatron-Bridge
git clone https://github.com/NVIDIA-NeMo/Megatron-Bridge.git
cd Megatron-Bridge
git checkout 5cb3444c43f7499cf3872b2d46870cf8bc2e00ce
git submodule update --init --recursive

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Cloning the Megatron-Bridge repository from GitHub at runtime on all 64 nodes simultaneously can lead to GitHub rate-limiting, slow startup times, and will fail entirely in private GKE clusters without internet access. Consider pre-building these dependencies into a custom container image or using an init container with a shared volume to clone it once.

--rdzv_id="${JOB_IDENTIFIER}" \
--master_addr="${MASTER_ADDR}" \
--master_port="${MASTER_PORT}" \
--no-python bash worker_command.sh 2>&1 | python3 -u -c "import sys, time; [sys.stdout.write('[{}] {}'.format(time.strftime('%Y-%m-%d %H:%M:%S'), line)) for line in iter(sys.stdin.readline, '')]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a list comprehension [sys.stdout.write(...) for line in ...] for its side effects causes Python to accumulate a list of return values (integers representing bytes written) in memory for the entire duration of the training run. For long-running jobs with large log volumes, this will lead to unnecessary memory growth. Use sys.stdout.writelines with a generator expression instead to process the stream lazily without memory overhead.

Suggested change
--no-python bash worker_command.sh 2>&1 | python3 -u -c "import sys, time; [sys.stdout.write('[{}] {}'.format(time.strftime('%Y-%m-%d %H:%M:%S'), line)) for line in iter(sys.stdin.readline, '')]"
--no-python bash worker_command.sh 2>&1 | python3 -u -c "import sys, time; sys.stdout.writelines('[{}] {}'.format(time.strftime('%Y-%m-%d %H:%M:%S'), line) for line in iter(sys.stdin.readline, ''))"

Comment on lines +163 to +172
{{- range $gcs := $root.Values.volumes.gcsMounts }}
- name: "{{ $gcs.bucketName }}"
csi:
driver: gcsfuse.csi.storage.gke.io
volumeAttributes:
bucketName: "{{ $gcs.bucketName }}"
{{- if $gcs.mountOptions }}
mountOptions: "{{ $gcs.mountOptions }}"
{{- end }}
{{- end}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If volumes.gcsMounts contains null placeholders (as defined by default in values.yaml), the template will render invalid volume definitions with name "null" and bucketName "null". Wrap the volume rendering in a check for if $gcs.bucketName to avoid rendering empty/invalid mounts.

            {{- range $gcs := $root.Values.volumes.gcsMounts }}
            {{- if $gcs.bucketName }}
            - name: "{{ $gcs.bucketName }}"
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: "{{ $gcs.bucketName }}"
                  {{- if $gcs.mountOptions }}
                  mountOptions: "{{ $gcs.mountOptions }}"
                  {{- end }}
            {{- end }}
            {{- end}}

Comment on lines +205 to +210
resources:
requests:
nvidia.com/gpu: {{ $gpusPerNode }}
limits:
nvidia.com/gpu: {{ $gpusPerNode }}
claims:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The workload container does not specify any CPU or memory requests/limits. Since the pod uses a large shared-memory tmpfs volume of up to 250Gi (which consumes host memory), not specifying memory requests can lead to severe node overcommit and unpredictable Out-Of-Memory (OOM) kills by the kernel. It is highly recommended to set explicit CPU and memory requests/limits.

Comment on lines +401 to +404
{{- range $gcs := $root.Values.volumes.gcsMounts }}
- name: "{{ $gcs.bucketName }}"
mountPath: "{{ $gcs.mountPath }}"
{{- end }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If volumes.gcsMounts contains null placeholders (as defined by default in values.yaml), the template will render invalid volumeMount definitions with name "null" and mountPath "null". Wrap the volumeMount rendering in a check for if $gcs.bucketName to avoid rendering empty/invalid mounts.

                {{- range $gcs := $root.Values.volumes.gcsMounts }}
                {{- if $gcs.bucketName }}
                - name: "{{ $gcs.bucketName }}"
                  mountPath: "{{ $gcs.mountPath }}"
                {{- end }}
                {{- end }}

@ngu3
ngu3 requested a review from Alina-PANG August 13, 2026 04:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant