写点什么

绝了!k3s (k8s) 安装 ollama 运行 deepseek 全流程揭秘,yaml 全公开

  • 2025-03-05
    北京
  • 本文字数:3259 字

    阅读完需:约 11 分钟

🎯k3s (k8s) 环境搭建与 ollama 相关 yaml 文件部署


在容器编排的世界中,k3s (k8s) 无疑是备受瞩目的存在。此次聚焦在 k3s (k8s) 环境下安装 ollama,并实现运行 deepseek。首先映入眼帘的是一个关键的 yaml 文件 ——ollama.yaml 。这个文件犹如整个部署流程的指挥棒,规定各项参数和配置信息。ollama.yaml 内容如下:


# https://cloud.tencent.com/developer/article/2495842 环境变量
apiVersion: apps/v1kind: Deploymentmetadata: labels: app: ollama name: ollama namespace: moonfddspec: strategy: type: Recreate replicas: 1 selector: matchLabels: app: ollama template: metadata: labels: app: ollama spec: containers: - env: - name: OLLAMA_HOST value: "0.0.0.0" - name: OLLAMA_PORT value: "11434" - name: OLLAMA_NUM_PARALLEL value: "20" #默认是1 - name: OLLAMA_ORIGINS value: "*" - name: OLLAMA_MODELS value: "/root/.ollama/models" image: 'ollama/ollama:0.5.12' command: ["ollama", "serve"] imagePullPolicy: IfNotPresent name: ollama volumeMounts: - mountPath: /root/.ollama/models/ name: data resources: # nvidia.com/gpu: 1 # memory: "24Gi" # limits: # cpu: 200m # memory: 200Mi # requests: # cpu: 100m # memory: 100Mi - image: 'ollama/ollama:0.5.12' command: ["sh", "-c", "while true; do ollama run deepseek-r1:1.5b; sleep 5; done"] imagePullPolicy: IfNotPresent name: ollamacmd volumes: - name: data hostPath: path: /root/k8s/moonfdd/ollama/root/.ollama/models/ type: DirectoryOrCreate---apiVersion: v1kind: Servicemetadata: labels: app: ollama name: ollama namespace: moonfddspec: ports: - name: 11434-11434 port: 11434 protocol: TCP targetPort: 11434 nodePort: 11434 selector: app: ollama type: NodePort
复制代码


📊ollama 安装与运行实际效果展示


命令如下:


kubectl apply -f ollama.yaml
复制代码


运行结果如下:






💻Go 语言调用 deepseek 接口代码分析


单纯有 ollama 环境运行起来还不够,还需要有与之交互的代码来发挥它的功能,这里就出现了 Go 语言调用 deepseek 接口的代码。go 代码如下:


package main
import ( "bufio" "bytes" "encoding/json" "fmt" "net/http" "time")
type Message struct { Role string `json:"role"` Content string `json:"content"`}
// 修改请求结构体,添加 Stream 字段type DeepSeekRequest struct { Model string `json:"model"` Messages []Message `json:"messages"` MaxTokens int `json:"max_tokens,omitempty"` Temperature float64 `json:"temperature,omitempty"` Stream bool `json:"stream"` // 新增流式控制字段}
// 保持其他结构体不变...
const ( localAPIURL = "http://172.16.11.111:11434/v1/chat/completions")
func main() { fmt.Println("开始") requestData := DeepSeekRequest{ Model: "deepseek-r1:1.5b", Messages: []Message{ { Role: "user", Content: "微信公众号 福大大架构师每日一题 是谁", }, }, MaxTokens: 512000, Temperature: 1, Stream: true, // 启用流式模式 }
requestBody, err := json.Marshal(requestData) if err != nil { panic("JSON编码失败: " + err.Error()) }
// 配置更合理的超时时间 client := &http.Client{ Transport: &http.Transport{ DisableKeepAlives: true, // 🔴 关键设置:禁用连接复用 MaxIdleConns: 1, IdleConnTimeout: 30 * time.Second, }, Timeout: 10 * time.Minute, // 大模型响应时间较长 }
req, err := http.NewRequest("POST", localAPIURL, bytes.NewBuffer(requestBody)) if err != nil { panic("创建请求失败: " + err.Error()) } req.Header.Set("Content-Type", "application/json") req.Header.Set("Connection", "close") // 显式关闭连接 req.Close = true resp, err := client.Do(req) if err != nil { panic("请求发送失败: " + err.Error()) } defer resp.Body.Close()
// 流式响应处理 if resp.StatusCode != http.StatusOK { fmt.Printf("请求失败,状态码:%d\n", resp.StatusCode) return }
// 使用 Scanner 逐行读取流式响应 scanner := bufio.NewScanner(resp.Body) scanner.Buffer(make([]byte, 1024), 10*1024*1024) // 扩大缓冲区
for scanner.Scan() { rawData := scanner.Bytes() if len(rawData) == 0 { continue }
var chunk DeepSeekChunk err := json.Unmarshal(rawData[6:], &chunk) if err == nil { for i := 0; i < len(chunk.Choices); i++ { fmt.Print(chunk.Choices[i].Delta.Content) } } else { if string(rawData) == string("data: [DONE]") {
} else { fmt.Println("\r\n接收失败:", err, string(rawData)) } return }
}
// if err := scanner.Err(); err != nil { // fmt.Printf("\n流读取错误: %v\n", err) // }}
// DeepSeekChunk 定义与提供的JSON结构相对应的结构体type DeepSeekChunk struct { ID string `json:"id"` Object string `json:"object"` Created int64 `json:"created"` Model string `json:"model"` SystemFingerprint string `json:"system_fingerprint"` Choices []Choice `json:"choices"`}
type Choice struct { Index int `json:"index"` Delta Delta `json:"delta"` FinishReason *string `json:"finish_reason,omitempty"` // 使用指针以处理可能为null的情况 //null "stop"}
type Delta struct { Role string `json:"role"` Content string `json:"content"`}
复制代码


运行结果如下:



官网不联网运行结果如下:



官网联网运行结果如下:



🎊实际意义与展望


通过在 k3s (k8s) 上完成 ollama 的安装并运行 deepseek,以及编写 Go 语言调用接口代码这一系列操作,具有多方面的实际意义和深远的展望。从技术层面而言,这为开发者在特定的容器编排环境下集成模型服务提供了一套可参考的方法和实践经验。无论是对于后续想要在相似环境里部署其他模型,还是改进和优化当前模型的运行方式,都提供了宝贵参考范例。从应用场景角度来看,能够在这样的技术栈下调用模型进行文本处理、问答交互等,都能为诸多实际项目开发提供强大助力。比如开发智能客服系统、智能助手应用等。展望未来,这种技术实践将不断推动相关技术的发展和融合。随着模型的不断升级迭代,我们可以期待更多强大功能能够被整合进这样的环境里 。同时,通过持续改进和优化 yaml 文件配置以及代码实现细节,将进一步提升系统的性能和稳定性。也相信会有更多开发者基于此进行创新和拓展,探索出更多的应用可能和技术思路。就像一颗石子投入平静湖面,会泛起层层涟漪般,这项技术实践也将在整个技术领域里引发新的探索和变革浪潮。

发布于: 2025-03-05阅读数: 2
用户头像

公众号:福大大架构师每日一题 2021-02-15 加入

公众号:福大大架构师每日一题

评论

发布
暂无评论
绝了!k3s (k8s) 安装 ollama 运行 deepseek 全流程揭秘,yaml全公开_福大大架构师每日一题_福大大架构师每日一题_InfoQ写作社区