Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/core-concepts/architecture.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
---
title: Architecture
title: Architecture Overview

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

four page titles are renamed in this pr with no stated reason, and the zh titles now diverge. revert or explain.

sidebar_label: Architecture
tags:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the zh copies of these six pages get no tags, so the feature silently does not exist in zh. also note docs tags render visible tag chips and generate /docs/tags pages, confirm that side effect is wanted.

- installation
- nvidia
- hami
- local-setup
---

The overall architecture of HAMi is shown as below:
Expand Down
7 changes: 6 additions & 1 deletion docs/core-concepts/ecosystem-integrations.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
title: Ecosystem Integrations
title: Ecosystem Integration Partners
sidebar_label: Ecosystem Integrations
tags:
- volcano
- kueue
- kai-scheduler
---

HAMi doesn't replace your Kubernetes scheduler. It extends it. HAMi handles GPU virtualization, sharing, and runtime isolation, and it slots into the wider Kubernetes scheduling world so you can pair **GPU sharing** with **batch scheduling, job queuing, and colocation**.
Expand Down
7 changes: 6 additions & 1 deletion docs/core-concepts/gpu-driver.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
---
title: "Understanding GPU Drivers"
title: "Understanding NVIDIA GPU Drivers in Kubernetes"
sidebar_label: "GPU Driver"
tags:
- nvidia
- simulation
- nvml-mock
---

Before using a GPU, you first need to verify that the GPU driver is properly loaded into the kernel. This document explains how to check GPU driver status and understand the architecture of NVIDIA kernel modules.
Expand Down
8 changes: 7 additions & 1 deletion docs/core-concepts/gpu-stack.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
---
title: "GPU Software Stack Overview"
title: "The GPU Software Stack"
sidebar_label: "GPU Stack"
tags:
- installation
- nvidia
- simulation
- nvml-mock
---

When you use a GPU on a server, you are not dealing with a single piece of software or hardware. Instead, you are working with an entire **software stack** built around NVIDIA GPUs. From the lowest-level physical hardware to the highest-level Kubernetes scheduling, it can be roughly divided into 5 layers:
Expand Down
8 changes: 8 additions & 0 deletions docs/core-concepts/gpu-virtualization.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
---
title: GPU Virtualization Principles
sidebar_label: GPU Virtualization
tags:
- gpu-partitioning
- isolation
- vllm
- inference
- alibaba-cloud
- resource-sharing
- hami
---

In AI inference scenarios, a common dilemma is that GPUs are expensive, but mostly idle.
Expand Down
7 changes: 7 additions & 0 deletions docs/core-concepts/hami-architecture.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
---
title: "HAMi Cluster Architecture After Installation"
sidebar_label: HAMi Architecture
tags:
- simulation
- nvml-mock
- hami
- scheduling
- local-setup
---

After completing the HAMi installation, the cluster is no longer an ordinary Kubernetes cluster, it becomes an AI infrastructure platform with GPU virtualization capabilities. This document breaks down the responsibilities and dependencies of every layer and every component in the cluster after installation.
Expand Down
50 changes: 50 additions & 0 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,55 @@ function getDocEditUrl(versionDocsDirPath, docPath) {
return `${githubEditBaseUrl}${[versionDocsDirPath, docPath].filter(Boolean).join("/")}`;
}

/**
* Build-time helper: scans tutorials/labs/*.md and extracts the metadata
* that the RelatedLabs component needs at runtime. This avoids the need
* to cross-reference two separate docs-plugin instances on the client.
*/
function getLabData() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

hand rolled frontmatter regex is fragile, level: also matches toc_max_heading_level on unlucky ordering. gray-matter ships with docusaurus, use it.

const fs = require("fs");
const path = require("path");
const labsDir = path.join(__dirname, "tutorials", "labs");
if (!fs.existsSync(labsDir)) return {};
const files = fs.readdirSync(labsDir).filter((f) => f.endsWith(".md"));
const labs = {};
for (const file of files) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const raw = fs.readFileSync(path.join(labsDir, file), "utf8");
// Normalise CRLF → LF so the regex works on every OS
const content = raw.replace(/\r\n/g, "\n");
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (!fmMatch) continue;
const fm = fmMatch[1];

const titleMatch = fm.match(/^title:\s*"?(.+?)"?\s*$/m);
const descMatch = fm.match(/^description:\s*"?(.+?)"?\s*$/m);
const levelMatch = fm.match(/level:\s*(.+)/);
const durationMatch = fm.match(/duration:\s*(.+)/);
const tagsMatch = fm.match(/^tags:\s*\n((?:\s+-\s+.*\n?)+)/m);

const tags = tagsMatch
? tagsMatch[1]
.split("\n")
.filter((l) => l.trim().startsWith("-"))
.map((l) => l.replace(/^\s*-\s*/, "").trim())
.filter(Boolean)
: [];

if (tags.length === 0) continue;

const docId = `labs/${file.replace(".md", "")}`;
labs[docId] = {
title: titleMatch ? titleMatch[1] : file.replace(".md", ""),
description: descMatch ? descMatch[1] : "",
level: levelMatch ? levelMatch[1].trim() : "",
duration: durationMatch ? durationMatch[1].trim() : "",
tags,
href: `/tutorials/${docId}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

href is not locale prefixed, zh concept pages will link to the english labs. build the url with the active locale, same issue i flagged on #774.

};
}
return labs;
}

async function localizedBlogPlugin(context, opts) {
const p = await require("@docusaurus/plugin-content-blog").default(context, opts);
const orig = p.postBuild?.bind(p);
Expand Down Expand Up @@ -71,6 +120,7 @@ module.exports = {
},
customFields: {
defaultOgImage: "/img/hami-graph-color.png",
labData: getLabData(),
},
markdown: {
mermaid: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ import LabCardGridAuto from '@site/src/components/labs/LabCardGridAuto';

<LabCardGridAuto />

每个实验都列出了各自的前提条件。实验 3 和 4 直接复用实验 1 搭建的集群,一次开机即可完成全部三个实验;实验 2 可在任意笔记本上运行,无需 GPU。实验 7 在租用的 GPU 虚拟机上自行搭建单节点 k3s 集群,不使用 GPU Operator。实验 8 需要已有的 Volcano GPU 集群,用于验证 Volcano vGPU、Gang 调度和队列级资源限制。实验 9 使用 Kueue 准入控制限制 HAMi vGPU 数量、显存和算力配额。实验 11 将从头搭建完整的 KServe Standard 推理环境,并通过 HAMi 原生 DRA Claim 让两个 vLLM 副本共享一张 GPU。实验 12 在 GKE 1.35/COS/CDI 上部署 KAI Scheduler 与 HAMi-core,并通过 CUDA 分配验证显存上限。实验 13 在昇腾 310P3 ARM 服务器上源码编译 Volcano 与 ascend-device-plugin,验证 hami-vnpu-core 软切分、binpack 共卡与容器级监控指标。
每个实验都列出了各自的前提条件。实验 3 和 4 直接复用实验 1 搭建的集群,一次开机即可完成全部三个实验;实验 2 可在任意笔记本上运行,无需 GPU。实验 7 在租用的 GPU 虚拟机上自行搭建单节点 k3s 集群,不使用 GPU Operator。实验 8 需要已有的 Volcano GPU 集群,用于验证 Volcano vGPU、Gang 调度和队列级资源限制。实验 9 使用 Kueue 准入控制限制 HAMi vGPU 数量、显存和算力配额。实验 11 将从头搭建完整的 KServe Standard 推理环境,并通过 HAMi 原生 DRA Claim 让两个 vLLM 副本共享一张 GPU。实验 12 在 GKE 1.35/COS/CDI 上部署 KAI Scheduler 与 HAMi-core,并通过 CUDA 分配验证显存上限。实验 13 在昇腾 310P3 ARM 服务器上源码编译 Volcano 并使用官方 v1.4.0 镜像部署 ascend-device-plugin,验证 hami-vnpu-core 软切分、binpack 共卡与容器级监控指标。

2 changes: 1 addition & 1 deletion src/components/labs/LabCardGridAuto.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import styles from "./LabCardGrid.module.css";
// Keyed by the English label, like LEVELS in LevelBadge. The ids have to be
// static or `write-translations` has nothing to extract; passing the sidebar
// value straight to <Translate> leaves the extractor with a runtime expression.
const DURATIONS = {
export const DURATIONS = {
"about 30 minutes": (
<Translate id="tutorials.lab.duration.30min" description="Lab duration of about 30 minutes">
about 30 minutes
Expand Down
96 changes: 96 additions & 0 deletions src/components/labs/RelatedLabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* RelatedLabs – tag-based, cross-plugin related-labs section.
*
* Concept pages (docs plugin) and lab pages (tutorials plugin) live in
* two separate Docusaurus docs-plugin instances, so we cannot use
* useDocsSidebar/useDocsVersion to reach across the boundary.
*
* Instead, the build-time helper `getLabData()` in docusaurus.config.js
* extracts every lab's metadata (title, description, level, duration,
* tags, href) and injects it into `siteConfig.customFields.labData`.
* This component reads that static map and matches tags at render time.
*/
import React from "react";
import Link from "@docusaurus/Link";
import Translate from "@docusaurus/Translate";
import { useDoc } from "@docusaurus/plugin-content-docs/client";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import LevelBadge from "./LevelBadge";
import styles from "./RelatedLabs.module.css";
import gridStyles from "./LabCardGrid.module.css";

import { DURATIONS } from "./LabCardGridAuto";

/**
* Renders a "Related Hands-on Labs" card grid at the bottom of doc pages.
*
* Reads the current page's frontmatter `tags` and matches them against
* pre-extracted lab metadata from `siteConfig.customFields.labData`.
* Labs with the most overlapping tags appear first. If the page has no
* tags or no labs match, the component renders nothing.
*
* @returns {React.ReactElement|null} A styled card grid of related labs, or null.
*/
export default function RelatedLabs() {
const { frontMatter } = useDoc();
const { siteConfig } = useDocusaurusContext();
const pageTags = frontMatter?.tags ?? [];

// Nothing to match against – render nothing.
if (pageTags.length === 0) {
return null;
}

const labData = siteConfig.customFields?.labData ?? {};
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Build cards for labs whose tags overlap with the current page's tags.
const matchedCards = Object.entries(labData)
.map(([docId, lab]) => {
const labTags = lab.tags ?? [];
const matchCount = labTags.filter((tag) => pageTags.includes(tag)).length;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the theme is shared across both docs plugin instances, so lab pages themselves render this section and match their own tags, including a card linking to the page you are already on. exclude the current doc id, or skip rendering inside the tutorials instance.

if (matchCount === 0) return null;
return {
key: docId,
href: lab.href,
title: lab.title,
description: lab.description,
level: lab.level,
duration: lab.duration,
matchCount,
};
})
.filter(Boolean)
.sort((a, b) => b.matchCount - a.matchCount || a.key.localeCompare(b.key))
.slice(0, 4); // Cap to top 4 to avoid long lists of loosely related labs

if (matchedCards.length === 0) {
return null;
}

return (
<div className={styles.container}>
<h3 className={styles.heading}>
<span className={styles.icon}>🔬</span>
<Translate id="theme.docs.relatedLabs.title" description="Title for related labs section">
Related Hands-on Labs
</Translate>
</h3>
<div className={gridStyles.grid}>
{matchedCards.map((card) => (
<Link key={card.key} to={card.href} className={gridStyles.card}>
<div className={gridStyles.cardHeader}>
<span className={gridStyles.cardTitle}>{card.title}</span>
<LevelBadge level={card.level} />
</div>
{card.description && <p className={gridStyles.cardDescription}>{card.description}</p>}
{card.duration && (
<div className={gridStyles.cardFooter}>
{DURATIONS[card.duration] ?? card.duration}
</div>
)}
</Link>
))}
</div>
</div>
);
}
27 changes: 27 additions & 0 deletions src/components/labs/RelatedLabs.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.container {
margin: 3rem 0;
padding: 1.5rem;
background-color: var(--ifm-color-emphasis-100);
border-radius: var(--ifm-global-radius);
border-left: 4px solid var(--ifm-color-primary);
}

.heading {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 0;
margin-bottom: 1rem;
font-size: 1.25rem;
color: var(--ifm-color-emphasis-900);
}

.icon {
font-size: 1.5rem;
}

/* Ensure grid overrides its top margin when inside container */
.container > div {
margin-top: 0;
margin-bottom: 0;
}
11 changes: 8 additions & 3 deletions src/theme/DocItem/Content/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/**
* Custom swizzle of DocItem/Content.
* Identical to the original except that the lab metadata row (LabMeta)
* renders directly below the page title for docs that carry a `lab`
* front matter block. Docs without it are unaffected.
*
* Additions on top of the Docusaurus default:
* - LabMeta: renders a metadata row (level, duration, authors) directly
* below the page title for docs that carry a `lab` front matter block.
* - RelatedLabs: renders a tag-matched grid of related hands-on labs
* at the bottom of any doc page that carries `tags` in its front matter.
*/
import React from "react";
import clsx from "clsx";
Expand All @@ -11,6 +14,7 @@ import { useDoc } from "@docusaurus/plugin-content-docs/client";
import Heading from "@theme/Heading";
import MDXContent from "@theme/MDXContent";
import LabMeta from "@site/src/components/labs/LabMeta";
import RelatedLabs from "@site/src/components/labs/RelatedLabs";

/**
Title can be declared inside md content or declared through
Expand Down Expand Up @@ -42,6 +46,7 @@ export default function DocItemContent({ children }) {
)}
<LabMeta />
<MDXContent>{children}</MDXContent>
<RelatedLabs />
</div>
);
}
3 changes: 2 additions & 1 deletion tutorials/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ Background knowledge that the labs build on.

## Labs

<LabCardGridAuto /> Each lab lists its own prerequisites. Labs 3 and 4 continue from the cluster Lab 1 builds, so a single session covers all three; Lab 2 runs on any laptop with no GPU required. Lab 7 brings up its own single-node k3s cluster on a rented GPU VM, without the GPU Operator. Lab 8 requires an existing Volcano GPU cluster and validates Volcano vGPU, Gang scheduling, and queue-level limits. Lab 9 uses Kueue admission control to enforce HAMi vGPU count, memory, and compute quotas. Lab 11 builds a complete KServe Standard inference stack and runs two vLLM replicas on one GPU through native HAMi DRA claims. Lab 12 deploys KAI Scheduler and HAMi-core on GKE 1.35/COS/CDI and proves the memory ceiling with CUDA allocations. Lab 13 builds Volcano and the ascend-device-plugin from source on an Ascend 310P3 ARM server and verifies hami-vnpu-core soft slicing, binpack card sharing, and per-container metrics.
<LabCardGridAuto /> Each lab lists its own prerequisites. Labs 3 and 4 continue from the cluster Lab 1 builds, so a single session covers all three; Lab 2 runs on any laptop with no GPU required. Lab 7 brings up its own single-node k3s cluster on a rented GPU VM, without the GPU Operator. Lab 8 requires an existing Volcano GPU cluster and validates Volcano vGPU, Gang scheduling, and queue-level limits. Lab 9 uses Kueue admission control to enforce HAMi vGPU count, memory, and compute quotas. Lab 11 builds a complete KServe Standard inference stack and runs two vLLM replicas on one GPU through native HAMi DRA claims. Lab 12 deploys KAI Scheduler and HAMi-core on GKE 1.35/COS/CDI and proves the memory ceiling with CUDA allocations. Lab 13 builds Volcano from source and deploys ascend-device-plugin from the official v1.4.0 image on an Ascend 310P3 ARM server, verifying hami-vnpu-core soft slicing, binpack card sharing, and per-container metrics.