Ollama 是一个简化大型语言模型部署和交互的框架,无需复杂的设置。它支持流行模型如 Llama(多个版本)、Mistral 等,所有这些模型均基于变压器架构。Ollama 允许我们运行自己的模型,无需依赖任何第三方模型提供商,因此可以始终保持信息的私密性,并使支出更加可预测和控制。
本文将创建 Azure 资源以在具有 GPU 支持的 Azure Kubernetes 服务管理集群上作为容器化容器运行 Ollama。除了常规的 Kubernetes 部署之外,还需要一些额外的步骤来允许集群将 GPU 识别为可分配资源并将其调度到这些资源。
先决条件:将使用 Terraform 及其 azurerm
提供程序,因此,我们需要在我们的工作站上安装以下组件。
此外,由于我们将使用配备GPU的虚拟机(例如NCv3
)来创建节点池(node pool),因此需要确保在我们计划使用的区域(例如eastus
)有足够的可用vCPU配额。
一个完整的Terraform脚本示例,该脚本创建一个私有网络,以及一个Azure Kubernetes服务(AKS)集群,并包含一个启用GPU的节点池、启用GPU资源的Nvidia容器以及Ollama容器,可以在以下GitHub仓库中找到,請参见以下GitHub仓库:
GitHub - ItayPodhajcer/terraform-ollama-aks 通过在GitHub上创建账户来参与ItayPodhajcer/terraform-ollama-aks的开发。 脚本为了简洁,我将仅涵盖与启用和稍后安排调度与依赖GPU的工作负载相关的该Terraform脚本部分。
在定义了 Azure Kubernetes 服务资源之后,我们将创建 GPU 节点组。
资源 "azurerm_kubernetes_cluster_node_pool" "this" { 名称 = "gpu" Kubernetes集群ID = azurerm_kubernetes_cluster.this.id VM大小 = "Standard_NC6s_v3" 节点计数 = 1 VNet子网ID = var.subnet_id 节点标签 = { "nvidia.com/gpu.present" = "true" } 节点污点 = ["sku=gpu:NoSchedule"] }
注意标签 “nvidia.com/gpu.present” = “true”
,这表示 Nvidia Device Plugin
的 pod 将被调度到该节点,以及 sku=gpu:NoSchedule
的污点标记,这阻止了未明确指定该容忍度的 pod 被调度到该节点(因为我们只希望将需要 GPU 的 pod 调度到该节点)。
接下来,我们创建两个 helm
资源,一个用于运行由 Nvidia 提供的 Nvidia Device Plugin
的 helm
chart(https://nvidia.github.io/k8s-device-plugin/nvidia-device-plugin
),另一个用于运行由 Outworld 提供的 Ollama
的 helm
chart(https://otwld.github.io/ollama-helm/ollama
)。
资源 "helm_release" "nvidia_device_plugin" { 名字 = "nvidia-device-plugin" 仓库 = "https://nvidia.github.io/k8s-device-plugin" 图表名 = "nvidia-device-plugin" 版本 = var.nvidia_device_plugin_chart_version 命名空间 = var.deployment_name 创建命名空间 = true 值列表 = [ "${templatefile("${path.module}/nvidia-device-plugin-values.tpl", { tag = var.nvidia_device_plugin_tag })}" ] }
使用了 nvidia-device-plugin-values.tpl
值模板文件的
image: tag: "${tag}" tolerations: - key: CriticalAddonsOnly operator: Exists - key: nvidia.com/gpu operator: Exists effect: NoSchedule - key: "sku" operator: Equal value: gpu effect: NoSchedule
和
资源 "helm_release" "ollama" { 名字 = local.ollama_service_name 仓库 = "https://otwld.github.io/ollama-helm/" 图表名称 = "ollama" 版本 = var.ollama_chart_version 命名空间 = var.deployment_name 创建命名空间 = true 配置值 = [ "${templatefile("${path.module}/ollama-values.tpl", { 标签 = var.ollama_tag 端口 = var.ollama_port 资源组 = azurerm_resource_group.this.name IP 地址 = azurerm_public_ip.this.ip_address DNS 标签名称 = local.ollama_service_name })}" ] 依赖项 = [helm_release.nvidia_device_plugin] }
使用 ollama-values.tpl
值模板文件,该文件中的模型为 llama3
,我们将运行此模型。
image: tag: "${tag}" ollama: gpu: enabled: true models: - llama3 service: type: 负载均衡器 port: ${port} annotations: service.beta.kubernetes.io/azure-load-balancer-resource-group: "${resource_group}" service.beta.kubernetes.io/azure-load-balancer-ipv4: "${ip_address}" service.beta.kubernetes.io/azure-dns-label-name: "${dns_label_name}" tolerations: - key: "sku" operator: "Equal" value: "gpu" effect: "不可调度"
注意以下附加的注释,这些注释将允许自动为该服务创建一个公共主机名,该主机名将基于以下定义的IP地址,以便稍后进行测试。
资源 "azurerm_public_ip" "this" { 名称 = "pip-${local.ollama_service_name}-${var.location}" location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name 分配方法 = "Static" sku = "Standard" 生命周期 { ignore_changes = [ domain_name_label ] } }
一旦所有资源定义完毕,我们需要运行 terraform apply
将所有内容部署到 Azure(如果你最近尚未登录,可能需要先运行 az login
命令)。
部署完成后,现在我们可以使用任何支持发送HTTP POST
请求的工具向我们的集群发送请求,例如cUrl
。
curl http://<ollama-service-hostname>:11434/api/generate -d '{ "model": "llama3", "prompt": "天空为什么是蓝色的?", "stream": false }'
并从模型中获取生成的响应,以及生成过程的其他统计信息。
结论部分本文中,我们使用了当时最简单的途径(至少在撰写本文时)在Kubernetes上运行需要GPU的任务。一些其他选项,如Nvidia的GPU Operator和Triton推理服务器,允许更高级的配置和更好地利用GPU资源,可以显著提高使用GPU虚拟机的成本效益,但代价是增加了复杂度。这种权衡取决于系统对AI的依赖程度,也就是说,系统越依赖GPU,从更高级的选项中获得的成本效益就越大。