码龙大大头像
关注

Python 基础设施即代码:用 Terraform + Ansible 管 AI 训练环境

Python 基础设施即代码:用 Terraform + Ansible 管 AI 训练环境

一、"我的 GPU 训练任务跑了 3 天,被同事的 Jupyter Notebook 把显存吃光了"

这是一个 AI 团队的真实笑话——也是痛点。团队有 4 块 A100 GPU,但没有任何资源管理和调度机制。大家 SSH 上去手动跑训练脚本,经常一个人占满显存,其他人干等着。更糟的是,每次有新同事入职,需要手动配环境(CUDA、cuDNN、PyTorch 版本),经常出现"在我机器上能跑啊"的问题。

基础设施即代码(IaC)不只是 DevOps 的事,AI 团队的训练环境更需要 IaC——因为环境配置错了,不是服务宕机 5 分钟的问题,而是一个训练任务 3 天的结果作废。

二、AI 训练环境的 IaC 架构

核心思路:Terraform 管"有哪些机器",Ansible 管"机器上装了什么",Slurm/K8s 管"任务怎么分配"。三层各司其职。

三、落地方案

Terraform:GPU 实例声明式管理

# main.tf - AI 训练集群基础设施
terraform {
  required_version = ">= 1.5.0"
  backend "s3" {
    bucket = "ai-infra-terraform-state"
    key    = "training-cluster/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

# GPU 实例
resource "aws_instance" "gpu_node" {
  count         = var.gpu_node_count
  ami           = var.gpu_ami
  instance_type = "p4d.24xlarge" # 8x A100 40GB

  vpc_security_group_ids = [
    aws_security_group.gpu_cluster.id
  ]

  # EBS 用于系统盘
  root_block_device {
    volume_size = 200
    volume_type = "gp3"
    encrypted   = true
  }

  # 本地 NVMe SSD 用于临时数据(训练数据集缓存)
  ephemeral_block_device {
    device_name = "/dev/sdb"
  }

  tags = {
    Name        = "gpu-training-node-${count.index}"
    Environment = var.environment
    Team        = "ai-training"
    CostCenter  = "ai-research"
  }

  # 自动加入 Ansible 管理
  provisioner "local-exec" {
    command = <<-EOT
      echo "${self.private_ip}  gpu-node-${count.index}" >> inventory.ini
    EOT
  }
}

# 共享 NFS 存储
resource "aws_efs_file_system" "training_data" {
  creation_token = "ai-training-data"
  encrypted      = true

  lifecycle_policy {
    transition_to_ia = "AFTER_30_DAYS"
  }

  tags = {
    Name = "ai-training-datasets"
  }
}

resource "aws_efs_mount_target" "training_data" {
  count           = length(var.subnet_ids)
  file_system_id  = aws_efs_file_system.training_data.id
  subnet_id       = var.subnet_ids[count.index]
  security_groups = [aws_security_group.efs.id]
}

# 成本控制:非工作时间自动关机
resource "aws_autoscaling_schedule" "night_shutdown" {
  scheduled_action_name  = "night-shutdown"
  autoscaling_group_name = aws_autoscaling_group.gpu_nodes.name
  recurrence            = "0 22 * * *"  # 每晚22点
  min_size              = 0
  desired_capacity      = 0
  max_size              = 0
}

Ansible:CUDA 环境一键配置

# playbook.yml - AI 训练环境标准化部署
- name: 配置 GPU 训练节点
  hosts: gpu_nodes
  become: yes
  vars:
    cuda_version: "12.4"
    cudnn_version: "9.1.0"
    python_version: "3.11"
    pytorch_version: "2.4.0"
    # 关键版本锁定,避免"在我机器上能跑"问题

  tasks:
    - name: 安装 NVIDIA 驱动
      apt:
        name: nvidia-driver-550
        state: present
      register: driver_install

    - name: 重启(驱动安装后需要)
      reboot:
        reboot_timeout: 300
      when: driver_install.changed

    - name: 安装 CUDA Toolkit
      shell: |
        wget https://developer.download.nvidia.com/compute/cuda/{{ cuda_version }}/local_installers/cuda_{{ cuda_version }}_linux.run
        sh cuda_{{ cuda_version }}_linux.run --silent --toolkit
      args:
        creates: /usr/local/cuda-{{ cuda_version }}

    - name: 设置 CUDA 环境变量
      lineinfile:
        path: /etc/profile.d/cuda.sh
        line: "{{ item }}"
        create: yes
      loop:
        - 'export CUDA_HOME=/usr/local/cuda-{{ cuda_version }}'
        - 'export PATH=$CUDA_HOME/bin:$PATH'
        - 'export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH'

    - name: 安装 cuDNN
      unarchive:
        src: /tmp/cudnn-linux-x86_64-{{ cudnn_version }}.tar.xz
        dest: /usr/local/
        remote_src: no
        creates: /usr/local/cuda/include/cudnn.h

    - name: 安装 Miniconda(Python 环境隔离)
      shell: |
        wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O /tmp/miniconda.sh
        bash /tmp/miniconda.sh -b -p /opt/miniconda
      args:
        creates: /opt/miniconda/bin/conda

    - name: 创建 PyTorch 虚拟环境
      shell: |
        source /opt/miniconda/bin/activate
        conda create -n pytorch-{{ pytorch_version }} python={{ python_version }} -y
        conda activate pytorch-{{ pytorch_version }}
        pip install torch=={{ pytorch_version }} torchvision torchaudio \
            --index-url https://download.pytorch.org/whl/cu{{ cuda_version.split('.')[0] }}{{ cuda_version.split('.')[1] }}
      args:
        executable: /bin/bash
        creates: /opt/miniconda/envs/pytorch-{{ pytorch_version }}

    - name: 安装训练依赖
      pip:
        name:
          - transformers==4.44.0     # 版本锁定
          - datasets==2.21.0
          - accelerate==0.33.0
          - wandb==0.17.0            # 实验追踪
          - tensorboard==2.17.0
        virtualenv: /opt/miniconda/envs/pytorch-{{ pytorch_version }}
        state: present  # present 而不是 latest——避免自动升级
    
    - name: 验证 GPU 可用
      shell: |
        source /opt/miniconda/bin/activate pytorch-{{ pytorch_version }}
        python -c "import torch; assert torch.cuda.is_available(), 'GPU不可用!'; print(f'GPU: {torch.cuda.get_device_name(0)}, 显存: {torch.cuda.get_device_properties(0).total_mem/1e9:.0f}GB')"
      register: gpu_check
    - debug:
        msg: "{{ gpu_check.stdout }}"
      when: gpu_check.rc == 0

四、成本控制的 IaC 实践

AI 训练环境最大的隐性成本是"空闲的 GPU"。一块 A100 每小时约 $3,如果 24/7 开机,月成本 $2160。4 块就是 $8640。而实际的训练时间每天可能只有 6-8 小时。

# 成本控制:自动扩缩容
resource "aws_autoscaling_group" "gpu_nodes" {
  min_size = 0          # 允许缩到 0(非工作时间)
  max_size = var.gpu_node_count
  
  tag {
    key   = "AutoShutdown"
    value = "true"
  }
}

# Lambda 函数:检测空闲 GPU(15分钟利用率 < 10% 时自动 shutdown)
# 配合 Slurm 的任务队列:
# - 当有任务排队时:自动启动 GPU 节点
# - 当任务队列为空 + GPU 空闲 > 15 分钟:自动关机

实际节省:GPU 使用时长从 720 小时/月(24/7)降到约 400 小时/月(按需使用),月成本从 $8640 降到约 $4800,节省了 45%。

五、总结

AI 训练环境的 IaC 三件套:Terraform(管资源)、Ansible(管环境)、Slurm/K8s(管调度)。核心价值不是"自动化"(那是最基本的),而是"可复现"——任何一个新节点拉起来,环境完全一致。版本锁定的重要性被低估——CUDA 12.4 和 12.5 的 PyTorch 行为可能有细微差异,训练结果不能复现时排查这个问题能浪费数天。最后,GPU 空闲成本是最大的浪费——用 Auto Scaling + 队列驱动的方式按需开关机,能有效控制成本。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/baronbool/article/details/163219247

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--