GPU 集群 IaC:Terraform + Ansible 部署自动化
GPU é群 IaCï¼Terraform + Ansible é¨ç½²èªå¨å
ä¼äººçéæç¬é 2026-08-17 0 é 读7åéAI å éå¨ç³»å · 第 6 ç¯
100 å° GPU æå¡å¨å°è´§ãæ¯å°è¦è£ 驱å¨ãCUDAãContainer RuntimeãGPU Operatorãé ç½® NCCL ç¯å¢åéãæå¨æ¥ï¼ä¸å° 30 åéï¼100 å° = ä¸å¨ãæ ¸å¿ææ³ï¼æ£ç¡®çäºæ å䏿¬¡ï¼ç¨ä»£ç éå¤ 100 éã
1. æå¨é¨ç½²æå¤çè¦
ä¸å°è£¸ GPU èç¹åæ K8s å¯è°åº¦å·¥ä½èç¹çä¾èµé¾ï¼
Kernel â GPU Driver â CUDA Toolkit â Container Runtime
â
âââââââââââââââââââââââââââ
â¼
GPU Operator â Workload (è®ç»/æ¨ç Pod)
â
âââ NCCL ç¯å¢åé
âââ InfiniBand / RoCE ç½å¡
âââ èç¹æ ç¾ & 污ç¹
æ¯ä¸å±é½å¯è½æï¼
- Driver vs Kernel ä¸å
¼å®¹ï¼NVIDIA 550.x è¦æ± Kernel 5.15+ï¼éåè·ç 5.19 HWEãNouveau 没ç¦ç¨å¹²åï¼è·éæºé©±å¨æ¢ GPU æ§å¶æââ
nvidia-smiç´æ¥æ¥éã - CUDA çæ¬éé
ï¼è®ç»æ¡æ¶è¦ CUDA 12.1ï¼ä½ è£
äº 11.8ãå®¹å¨ mount ç cuDNN è·ç¼è¯æ¶ä¸ä¸è´ââ
CUDNN_STATUS_VERSION_MISMATCHã - NCCL ç¯å¢åéå°±éäºä¸ä¸ªå¼ï¼
NCCL_SOCKET_IFNAMEæå管çç½å¡è䏿¯ RoCE ç½å¡ã64 å¡ AllReduce è·å¨ 1Gbps 管çç½ä¸ââ30 ç§ä¸åçåæ¥åæ 15 åéã
ä¸åææéè¿å·¥æ¶èæ¯åå§é¨ç½²ç 3 åââè¦å¨ 100 å°éæ¾åº"åªå å°é
éäºãåªä¸æ¥é
éäº"ãIaC åºå¯¹ï¼ä¸æ¬¡æ§æä¾èµé¾åè¿ä»£ç ï¼æµè¯éè¿å 100 å° = ansible-playbook -i inventory deploy.yml --forks 100ï¼30 åéå
¨é¨å°±ç»ªã
2. Terraformï¼åºç¡è®¾æ½å£°æå¼ç®¡ç
Terraform è§£å³"äºèµæºä»æ å°æ"ã.tf æä»¶é声æä½ è¦ä»ä¹ï¼å®ç®åºæä¹åè¿å»ã
GPU é群ä¸å¤§èµæºå
âââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Terraform State â
âââââââââââââââââ¬âââââââââââââââââââ¬âââââââââââââââââââ¤
â Compute â Network â Storage â
âââââââââââââââââ¼âââââââââââââââââââ¼âââââââââââââââââââ¤
â GPU å®ä¾ â ä½å»¶è¿ VPC â å¹¶è¡æä»¶ç³»ç» â
â èªå¨æ©ç¼©ç» â Placement Group â (Lustre/GPFS) â
â Spot/æ¢å å¼ â é«å¸¦å®½åç½ â 对象åå¨(模å) â
â â EFA/RDMA ç½å¡ â â
âââââââââââââââââ´âââââââââââââââââââ´âââââââââââââââââââ
Computeï¼H100 é群å³çââp5.48xlargeï¼8xH100 NVSwitchï¼+ Spot å®ä¾ï¼ç 70%ï¼+ Cluster æ¾ç½®ç»ï¼å䏿ºæ¶ï¼æå° NCCL å»¶è¿ï¼ã
Networkï¼å¤èç¹ GPU è®ç»ç¶é¢ä¸å¨è®¡ç®ââå¨ç½ç»ãPlacement Group strategy="cluster"ï¼NCCL Ring AllReduce å»¶è¿è·è·³æ°ç´æ¥ç¸å
³ï¼ï¼å¼¹æ§ç½å¡å管ç/æ°æ®å离ï¼å®å
¨ç»å¼æ¾ NCCL å¨æç«¯å£ã
Storageï¼è®ç»æ°æ®é©»çå¹¶è¡æä»¶ç³»ç»ï¼Lustreï¼100Gbps+ 带宽ï¼ï¼checkpoint å对象åå¨ãå建 FSx for Lustre æ¶ per_unit_storage_throughput >= 1000ââé»è®¤ 125 MB/s/TiB è¿è¿ä¸å¤ã
Terraform HCL æ ¸å¿ä»£ç
# placement.tf ââ æå
³é®
resource "aws_placement_group" "gpu_cluster" {
name = "h100-training-pg"
strategy = "cluster" # ç©çèéï¼æå°å NCCL å»¶è¿
}
# instances.tf
resource "aws_instance" "gpu_node" {
count = var.instance_count
ami = data.aws_ami.gpu_ubuntu.id
instance_type = "p5.48xlarge" # 8 Ã H100 80GB
placement_group = aws_placement_group.gpu_cluster.name
instance_market_options {
market_type = "spot" # è®ç»æ¯æ checkpoint å°±ç¨å®ï¼ç 70%
spot_options { instance_interruption_behavior = "terminate" }
}
dynamic "network_interface" {
for_each = var.enable_efa ? [1] : []
content {
network_interface_id = aws_network_interface.efa[count.index].id
device_index = 2 # æ°æ®é¢ç½å¡ââç¬ç«äºç®¡çç½
}
}
root_block_device {
volume_type = "gp3"
volume_size = 500
iops = 16000
}
tags = { Name = "gpu-node-${count.index}", ManagedBy = "terraform" }
}
# storage.tf
resource "aws_fsx_lustre_file_system" "training_data" {
storage_capacity = 4800
deployment_type = "PERSISTENT_2"
per_unit_storage_throughput = 1000 # é«ååä¸è½ç
subnet_ids = [aws_subnet.compute.id]
}
output "gpu_private_ips" {
value = aws_instance.gpu_node[*].private_ip # äº¤ç» Ansible çæ¡¥æ¢
}
Terraform çä»·å¼ä¸å¨äº"è½åå»ºèµæº"ââæ§å¶å°ä¹è½ç¹ãèå¨äºå䏿¬¡æ¨¡åï¼16 å°å 16000 å°çå·®å«åªæ¯ -var instance_count=16000ï¼å¹¶ä¸ plan è®©ä½ åæ´åå°±ç¥éä»ä¹ä¼è¢«å建/ä¿®æ¹/鿝ã
3. Ansibleï¼GPU èç¹çç»æé ç½®æå
Ansible çä¼å¿æ¯å¹çæ§ï¼playbook é夿§è¡ï¼å·²é å¥½çæ¥éª¤èªå¨è·³è¿ã
Playbook ç»æï¼ä¸¥æ ¼ä¾èµé¡ºåºï¼
00-prerequisites.yml â å
æ ¸åæ°ãç¦ç¨ NouveauãGCC/Make
01-nvidia-driver.yml â NVIDIA é©±å¨ + CUDA Toolkit
02-container-runtime.yml â nvidia-container-toolkit + containerd
03-gpu-operator.yml â Helm é¨ç½² GPU Operator
04-network-tuning.yml â NCCL ç¯å¢åéãRoCE/IB ç»å¡
05-validation.yml â GPU Burn + NCCL-Test
Step 0ï¼åç½®
- hosts: gpu_nodes
become: yes
tasks:
- lineinfile:
path: /etc/modprobe.d/blacklist-nouveau.conf
line: "blacklist nouveau"
create: yes
- copy:
dest: /etc/sysctl.d/99-gpu.conf
content: |
vm.max_map_count = 2147483647
kernel.numa_balancing = 0
- apt:
name: [build-essential, gcc, make, "linux-headers-{{ ansible_kernel }}"]
- reboot:
reboot_timeout: 300
vm.max_map_countï¼GPU åºç¨å建大éå
åæ å°ï¼numa_balancing=0ï¼å
³éèªå¨ NUMA 页é¢è¿ç§»ââé¿å
éæºå»¶è¿æå¨ã
Step 1ï¼é©±å¨ + CUDA
- hosts: gpu_nodes
become: yes
tasks:
- apt_repository:
repo: "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64 /"
- apt:
name: [nvidia-driver-550, cuda-toolkit-12-4]
- command: nvidia-smi --query-gpu=name,driver_version --format=csv,noheader
register: gpu_check
驱å¨çæ¬ååï¼ä¸è¿½ææ°ï¼è¿½æç¨³å®ãæ°æ®ä¸å¿é©±å¨å production branchï¼550.xï¼å new feature branchï¼560.xï¼ãè®ç»éç¾¤ç¨ productionã
Step 2ï¼Container Runtime
- hosts: gpu_nodes
become: yes
tasks:
- apt:
name: nvidia-container-toolkit
- shell: nvidia-ctk runtime configure --runtime=containerd
args:
creates: /etc/containerd/config.toml
- systemd:
name: containerd
state: restarted
enabled: yes
nvidia-container-toolkit æå®¿ä¸»æº GPU 驱å¨å CUDA åºéè¿ LD_PRELOAD å cgroup hooks "éä¼ "è¿å®¹å¨ââä¸éè¦æ¯ä¸ªéåæå
2GB CUDA è¿è¡æ¶ã
Step 3ï¼GPU Operator
- hosts: gpu_nodes[0]
tasks:
- kubernetes.core.helm:
name: gpu-operator
chart_ref: nvidia/gpu-operator
chart_version: "v24.3.0"
namespace: gpu-operator
create_namespace: yes
values:
driver.enabled: false # Ansible å·²è£
好驱å¨ââä¸è®© Operator éå¤è£
toolkit.enabled: true
devicePlugin.enabled: true
dcgm.enabled: true # DCGM Exporter â Prometheus GPU çæ§
migManager.enabled: false # è®ç»é群ä¸å MIG åå
gfd.enabled: true # èªå¨åç° GPU åå·å¹¶æèç¹æ ç¾
driver.enabled: falseï¼è®© Operator èªå·±è£
驱å¨ä¼æ¯èç¹è· DaemonSet ä»å®¹å¨éåæé©±å¨ï¼ç½ç»æ
¢æ¶è¶
æ¶ãé¢è£
æç¨³ã
Step 4ï¼NCCL ç½ç»è°ä¼ï¼æå®¹æåºäºçæ¥éª¤ï¼
NCCL æ¯å¤ GPU éä¿¡æ ¸å¿ââPyTorch DDP/FSDPãDeepSpeedãMegatron-LM åºå±é½è°å®ç AllReduce/AllGatherãè¡ä¸ºå ¨ç±ç¯å¢åéæ§å¶ââ设éä¸ä¸ªå¯è½ä¸æ¥éï¼ååå·® 40%ã
- hosts: gpu_nodes
become: yes
tasks:
- lineinfile:
path: /etc/environment
line: "{{ item }}"
loop:
- 'NCCL_SOCKET_IFNAME=eth1' # RoCE ç½å¡ââç»ä¸è½æç®¡çç½
- 'NCCL_IB_DISABLE=0' # å¯ç¨ InfiniBand
- 'NCCL_NET_GDR_LEVEL=5' # GPUDirect RDMAï¼æ¾åâç½å¡ï¼è·³è¿ CPU
- 'NCCL_PROTO=Simple' # RDMA é¶æ·è´
- 'NCCL_ALGO=Ring' # AllReduce Ringââ带宽æä¼
- 'NCCL_NSOCKS_PERTHREAD=4'
- 'NCCL_BUFFSIZE=4194304' # 4MBï¼å¹é
400Gbps ç½å¡
- 'NCCL_DEBUG=WARN'
NCCL ç¯å¢åé鿥
| åé | ä½ç¨ | æ¨èå¼ | 设éç代价 |
|---|---|---|---|
NCCL_SOCKET_IFNAME | éä¿¡ç½å¡ | eth1(RoCE) | 走管çç½âå»¶è¿çå¢âååå´©ç |
NCCL_IB_DISABLE | ç¦ç¨ IB | 0(å¯ç¨) | 贵价 IB é²ç½®âé级 TCP/IP |
NCCL_NET_GDR_LEVEL | GPUDirect RDMA | 5 | 设 0â4 次æ·è´ï¼è®¾ 5â1 次æ·è´ |
NCCL_ALGO | AllReduce ç®æ³ | Ring | é误é Treeâå¤§æ°æ®å¸¦å®½è¿ä½äº Ring |
NCCL_DEBUG | æ¥å¿çº§å« | WARN | INFOâæ¥å¿æçï¼ERRORâæ ææ¥çº¿ç´¢ |
NCCL_P2P_DISABLE | ç¦ç¨ P2P | ä¸è®¾(å¯ç¨) | èµ° host memoryâååæ 30% |
æ ¸å¿ååï¼è®©æ°æ®ä» GPU æ¾åå°å¯¹é¢ GPU æ¾åè·¯å¾æçãæ¯ä¸æ¥é´æ¥è®¿é®é½æ¯å»¶è¿ââAllReduce æ¯åæ¥æä½ï¼ä¸ä¸ªèç¹æ ¢ï¼å ¨åºçã
Step 5ï¼éªè¯ââè·å说è¯
- hosts: gpu_nodes
tasks:
- shell: docker run --rm --gpus all nvidia/cuda:12.4.0-devel-ubuntu22.04 \
bash -c "cd /gpu-burn && make && ./gpu_burn 120"
- shell: kubectl run nccl-test --rm -i --restart=Never \
--image=nvidia/cuda:12.4.0-devel-ubuntu22.04 \
--overrides='{"spec":{"containers":[{"name":"t","resources":{"limits":{"nvidia.com/gpu":8}}}]}}' \
-- mpirun -np 8 ./all_reduce_perf -b 8 -e 128M -f 2 -g 1
- command: nvidia-dcgm -r 1
GPU Burn æ´é²æ£çé®é¢ãä¾çµä¸è¶³ãPCIe ä¿¡å·é误ãNCCL-Testï¼8 å¡ H100 带宽ä¸å° 350 GB/sï¼ç论 400ï¼= é ç½®æé®é¢ã
4. 宿´æµæ°´çº¿
âââââââââââââ âââââââââââââââ âââââââââââââââ âââââââââââââ
â Terraform â ââââ â Ansible â ââââ â ArgoCD â ââââ â éªè¯éè¿ â
ââââââââââââ⤠ââââââââââââââ⤠ââââââââââââââ⤠âââââââââââââ¤
â å建 VPC â â åç½®åå¤ â â GPU Operatorâ â GPU Burn â
â å建å®ä¾ â â 驱å¨+CUDA â â K8s Pods â â NCCL-Test â
â å建åå¨ â â Container RTâ â è®ç» Job â â DCGM è¯æ â
â è¾åº IPs â â NCCL è°ä¼ â â â â â
âââââââââââââ âââââââââââââââ âââââââââââââââ âââââââââââââ
~10 åé ~15 åé ~5 åé ~2 åé
å®é å½ä»¤ï¼
# 1. Terraform å建åºç¡è®¾æ½
terraform apply -auto-approve
# 2. è¾åº IP åè¡¨çæ Ansible inventory
terraform output -json gpu_private_ips | jq -r '.[]' > inventory
# 3. Ansible å
¨éå¹¶è¡ââforks=100 æ¯å
³é®
ansible-playbook -i inventory site.yml --forks 100
# 4. ArgoCD æ¥ç®¡ï¼æ°èç¹èªå¨ sync
argocd app sync gpu-cluster
--forks 100 æ¯å
³é®ï¼Ansible é»è®¤ forks=5ï¼100 å°è· 20 è½®ã设 forks=100ï¼ææèç¹åæ¶é
ââæ»æ¶é´ = åå°æ¶é´ï¼~15 åéï¼ï¼è·èç¹æ°æ å
³ã
ä¸å¥è¯æ»ç»
Terraform 管"æä»ä¹"ï¼Ansible 管"æä¹é
"ãåè
声æ GPU é群åºå±èµæºââç½ç»ã计ç®ãåå¨ââä¸ä»½ä»£ç éé
å¤äºï¼åè
æè£¸éå±åæ GPU å·¥ä½èç¹ââä»å
æ ¸åæ°å° NCCL ç¯å¢åéï¼ä¾èµé¡ºåºç²¾ç¡®ï¼å¹çå¯éè¯ã两è
èåï¼100 å° GPU èç¹ä»é¶å°å¯è®ç»ï¼30 åéè䏿¯ä¸å¨ãNCCL ç¯å¢åéæ¯æ´æ¡é¾ä¸æè¢«å¿½è§çé·é±ââä¸ä¸ª NCCL_SOCKET_IFNAME 设éï¼è½è®© 8xH100 é群è·åº 1080Ti çéä¿¡æ§è½ã
ä¸ä¸ç¯ï¼GPU Operator 深度解æââ为ä»ä¹ä¸ä¸ª Helm Chart è½ç®¡ä½é©±å¨ãDevice PluginãDCGMãMIG å ¨é¨çå½å¨æï¼å®æ¯æä¹åç°æ° GPUãæä¹ç» Kubelet 注åèµæºãæä¹åå°"ä¸ä¸ª Pod ç³è¯· 0.5 å¼ GPU"çï¼
Aitishiku.com