开源项目one-api的k8s容器化部署(上)-- 制作镜像及部署准备
一、背景
最近需要对开源项目one-api进行k8s容器化部署,主要分以下几个步骤:
- 制作docker镜像
- 申请mysql和redis数据库
- docker-compose部署方式
- k8s部署方式
整个的篇幅比较长,将会分成上下两篇来阐述。
二、制作docker镜像
开源项目one-api已经提供了Dockerfile文件,按说制作一个私有镜像是非常简单的事情,可是却遇到了一个大坑。
主要是因为golang的版本问题。
官方Dockerfile所使用的是golang,并没有指定版本,也即golang:latest。
go version查看得到其版本为1.17。
这是我们要修改的第一点,指定golang的版本。
# 修改前
FROM golang AS builder2# 修改后
FROM golang:1.19-alpine AS builder2
golang:1.19-alpine
第二、我们在构建go项目的时候,增加国内镜像代理,以加速构建。
ENV GOPROXY=https://goproxy.cn,direct
第三、整个Dockerfile先是构建前端页面,再是构建go项目。本文主要是针对go项目的构建进行了改动。
完整的Dockerfile,修改后的内容,详见下:
# 指定golang的版本
FROM golang:1.19-alpine AS builder2# 增加go镜像代理
ENV GOPROXY=https://goproxy.cn,direct \GO111MODULE=on \CGO_ENABLED=1 \GOOS=linux# 切换工作目录至/build
WORKDIR /buildADD go.mod go.sum ./
RUN go mod download# 安装C编译器
RUN apk add --no-cache build-baseCOPY . .
COPY --from=builder /web/build ./web/build
RUN go build -ldflags "-s -w -X 'github.com/songquanpeng/one-api/common.Version=$(cat VERSION)' -extldflags '-static'" -o one-api# 总结这一阶段,会在工作目录/build下生成一个可执行文件one-api# 下面是把它单拎出去,使用轻量级容器alpine,运行该可执行文件。FROM alpineRUN apk update \&& apk upgrade \&& apk add --no-cache ca-certificates tzdata \&& update-ca-certificates 2>/dev/null || true# 把可执行文件/build/one-api拷贝至alpine系统的根目录/下
COPY --from=builder2 /build/one-api /EXPOSE 5175# 切换工作目录至/data
WORKDIR /data# 运行根目录下的可执行文件one-api
ENTRYPOINT ["/one-api"]
golang版本导致build报错
-
/go/pkg/mod/github.com/jackc/pgx/v5@v5.5.4/pgtype/builtin_wrappers.go:9:2: package net/netip is not in GOROOT (/usr/local/go/src/net/netip)
在Go 1.17及以后的版本中,net/netip包已经被移动到golang.org/x/net模块中。这个错误的解决办法就是升级go版本。 -
github.com/mattn/go-sqlite3 cgo: C compiler “gcc” not found: exec: “gcc”: executable file not found in $PATH
安装CGO所需的C编译器和库,在RUN go mod download后面,在RUN go build的前面,增加命令:RUN apk add --no-cache build-base。(因为golang:1.19-alpine使用musl libc,而不是glibc,并且默认不包含gcc) -
Step 20/29 : RUN go mod download
—> Running in f29cd7f8f144
go mod download: zip: not a valid zip file
这是因为网络慢导致的错误,解决版本是使用go镜像代理。 -
github.com/jackc/puddle/v2
/go/pkg/mod/github.com/jackc/puddle/v2@v2.2.1/pool.go:142:30: undefined: atomic.Int64
note: module requires Go 1.19
github.com/mattn/go-sqlite3
cgo: C compiler “gcc” not found: exec: “gcc”: executable file not found in $PATH
这个错误是当时使用了golang:1.19镜像,后修改为golang:1.19-alpine解决。
其他调试命令
如果你根据报错信息去修改的话,可能会需要打印一些环境信息。
- RUN go env
- RUN go version
- RUN echo $PATH
在构建docker镜像的过程中,还遇到许多报错,这里就不一一列举,报错的原因也都是因为golang的版本,期间使用过1.16/1.18/1.19,最后是使用1.19-alpine解决。
而one-api项目的go.mod文件指定使用1.18。
所以说,关于golang的版本问题很乱,我也是一通乱试。
三、关系型数据库DDL
在开发环境,我们只需新建数据库one_api即可。
但是,在生产环境,我们建议你手动建库建表.
CREATE DATABASE `one_api` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */;CREATE TABLE `one_api`.`abilities` (`group` varchar(32) COLLATE utf8mb4_bin NOT NULL,`model` varchar(191) COLLATE utf8mb4_bin NOT NULL,`channel_id` bigint(20) NOT NULL,`enabled` tinyint(1) DEFAULT NULL,`priority` bigint(20) DEFAULT '0',PRIMARY KEY (`group`,`model`,`channel_id`),KEY `idx_abilities_priority` (`priority`),KEY `idx_abilities_channel_id` (`channel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;CREATE TABLE `one_api`.`channels` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`type` bigint(20) DEFAULT '0',`key` text COLLATE utf8mb4_bin,`status` bigint(20) DEFAULT '1',`name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`weight` bigint(20) unsigned DEFAULT '0',`created_time` bigint(20) DEFAULT NULL,`test_time` bigint(20) DEFAULT NULL,`response_time` bigint(20) DEFAULT NULL,`base_url` varchar(191) COLLATE utf8mb4_bin DEFAULT '',`other` longtext COLLATE utf8mb4_bin,`balance` double DEFAULT NULL,`balance_updated_time` bigint(20) DEFAULT NULL,`models` longtext COLLATE utf8mb4_bin,`group` varchar(32) COLLATE utf8mb4_bin DEFAULT 'default',`used_quota` bigint(20) DEFAULT '0',`model_mapping` varchar(1024) COLLATE utf8mb4_bin DEFAULT '',`priority` bigint(20) DEFAULT '0',`config` longtext COLLATE utf8mb4_bin,PRIMARY KEY (`id`),KEY `idx_channels_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;CREATE TABLE `one_api`.`logs` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL,`created_at` bigint(20) DEFAULT NULL,`type` bigint(20) DEFAULT NULL,`content` longtext COLLATE utf8mb4_bin,`username` varchar(191) COLLATE utf8mb4_bin DEFAULT '',`token_name` varchar(191) COLLATE utf8mb4_bin DEFAULT '',`model_name` varchar(191) COLLATE utf8mb4_bin DEFAULT '',`quota` bigint(20) DEFAULT '0',`prompt_tokens` bigint(20) DEFAULT '0',`completion_tokens` bigint(20) DEFAULT '0',`channel_id` bigint(20) DEFAULT NULL,PRIMARY KEY (`id`),KEY `index_username_model_name` (`model_name`,`username`),KEY `idx_logs_token_name` (`token_name`),KEY `idx_logs_model_name` (`model_name`),KEY `idx_logs_channel_id` (`channel_id`),KEY `idx_logs_user_id` (`user_id`),KEY `idx_created_at_type` (`created_at`,`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;CREATE TABLE `one_api`.`options` (`key` varchar(191) COLLATE utf8mb4_bin NOT NULL,`value` longtext COLLATE utf8mb4_bin,PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;CREATE TABLE `one_api`.`redemptions` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL,`key` char(32) COLLATE utf8mb4_bin DEFAULT NULL,`status` bigint(20) DEFAULT '1',`name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`quota` bigint(20) DEFAULT '100',`created_time` bigint(20) DEFAULT NULL,`redeemed_time` bigint(20) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `idx_redemptions_key` (`key`),KEY `idx_redemptions_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;CREATE TABLE `one_api`.`tokens` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL,`key` char(48) COLLATE utf8mb4_bin DEFAULT NULL,`status` bigint(20) DEFAULT '1',`name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`created_time` bigint(20) DEFAULT NULL,`accessed_time` bigint(20) DEFAULT NULL,`expired_time` bigint(20) DEFAULT '-1',`remain_quota` bigint(20) DEFAULT '0',`unlimited_quota` tinyint(1) DEFAULT '0',`used_quota` bigint(20) DEFAULT '0',`models` varchar(191) COLLATE utf8mb4_bin DEFAULT '',`subnet` varchar(191) COLLATE utf8mb4_bin DEFAULT '',PRIMARY KEY (`id`),UNIQUE KEY `idx_tokens_key` (`key`),KEY `idx_tokens_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;CREATE TABLE `one_api`.`users` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`username` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`password` longtext COLLATE utf8mb4_bin NOT NULL,`display_name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`role` bigint(20) DEFAULT '1',`status` bigint(20) DEFAULT '1',`email` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`github_id` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`wechat_id` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`lark_id` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,`access_token` char(32) COLLATE utf8mb4_bin DEFAULT NULL,`quota` bigint(20) DEFAULT '0',`used_quota` bigint(20) DEFAULT '0',`request_count` bigint(20) DEFAULT '0',`group` varchar(32) COLLATE utf8mb4_bin DEFAULT 'default',`aff_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,`inviter_id` bigint(20) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `username` (`username`),UNIQUE KEY `idx_users_aff_code` (`aff_code`),UNIQUE KEY `idx_users_access_token` (`access_token`),KEY `idx_users_lark_id` (`lark_id`),KEY `idx_users_email` (`email`),KEY `idx_users_git_hub_id` (`github_id`),KEY `idx_users_we_chat_id` (`wechat_id`),KEY `idx_users_inviter_id` (`inviter_id`),KEY `idx_users_username` (`username`),KEY `idx_users_display_name` (`display_name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
最后,登录用户初始化一个root用户:
- dml语句:
INSERT INTO `one_api`.`users`
(id, username, password, display_name, `role`, status, email, github_id, wechat_id, lark_id, access_token, quota, used_quota, request_count, `group`, aff_code, inviter_id)
VALUES(1, 'root', '$2a$10$HAJRqAF884IGFJYvaAR.eu82GA8vNhQR.iQ0.jEYfovZNioyD91Te', 'Root User', 100, 1, '', '', '', '', '47d954235a724c399bfc3ea400eb3b2c', 500000000000000, 0, 0, 'default', '', 0);
四、redis数据库连接
非关系型数据库,不涉及ddl和dml了,仅给出连接地址的示例(区分有无密码)
-
无密码
redis://:192.168.80.116:6379 -
有密码
redis://:{password}:192.168.80.116:6379
五、docker-compose部署
测试并验证上面制作好的docker镜像,下文将把它部署到k8s容器里。
version: '3.4'services:one-api:image: "xxx/one-api:1.0.0"container_name: one-apirestart: alwayscommand: --port 5175ports:- "5175:5175"environment:- SQL_DSN=root:123456@tcp(192.168.80.116:3306)/one_api # 修改此行,或注释掉以使用 SQLite 作为数据库- REDIS_CONN_STRING=redis://:192.168.80.116:6379- SESSION_SECRET=random_string # 修改为随机字符串- TZ=Asia/Shanghai
[root@emc7 one-api]# docker-compose psName Command State Ports
-------------------------------------------------------------------------
one-api /one-api --port 5175 Up 0.0.0.0:5175->5175/tcp
六、推送镜像
验证docker镜像后,推送至远程仓库,为下文k8s部署做准备。
[root@emc7 one-api]# docker images | grep one
xxx/one-api 1.0.0 c290c605bd1b 6 hours ago 72.1MB
xxx-harbor-registry.cn-hangzhou.cr.aliyuncs.com/xxx/one-api-web 1.0.0 c290c605bd1b 6 hours ago 72.1MB[root@emc7 one-api]# docker tag c290c605bd1b xxx-harbor-registry.cn-hangzhou.cr.aliyuncs.com/xxx/one-api-web:1.0.0[root@emc7 one-api]# docker login --username={用户名} xxx-harbor-registry.cn-hangzhou.cr.aliyuncs.com --password {密码}[root@emc7 one-api]# docker push xxx-harbor-registry.cn-hangzhou.cr.aliyuncs.com/xxx/one-api-web:1.0.0
相关文章:

开源项目one-api的k8s容器化部署(上)-- 制作镜像及部署准备
一、背景 最近需要对开源项目one-api进行k8s容器化部署,主要分以下几个步骤: 制作docker镜像申请mysql和redis数据库docker-compose部署方式k8s部署方式 整个的篇幅比较长,将会分成上下两篇来阐述。 二、制作docker镜像 开源项目one-api…...

面试-数据库基础以及MySql、ClickHost、Redis简介
面试-数据库基础以及MySql、ClickHost、Redis简介 0.数据完整性1.数据库并发控制1.1事物1.2 并发读写错误1.3 锁1.3.1 乐观锁与悲观锁1.3.2 共享锁和排他锁1.3.3 行锁与表锁1.3.4 意向锁 1.4 封锁协议与隔离级别1.5 MVCC1.5.1 概念1.5.2 当前读与快照读1.5.3 MVCC in InnoDB 2.…...

MySQL分库分表的方式有哪些
目录 一、为什么要分库分表 二、什么是分库分表 三、分库分表的几种方式 1.垂直拆分 2. 水平拆分 四、分库分表带来的问题 五、分库分表技术如何选型 一、为什么要分库分表 如果一个网站业务快速发展,那这个网站流量也会增加,数据的压力也会随之而…...
数据结构课程设计选做(一)---数字排序(哈希、排序)
2.1.1 题目内容 2.1.1-A [问题描述] 给定n个整数,请统计出每个整数出现的次数,按出现次数从多到少的顺序输出。 2.1.1-B [基本要求] (1)输入格式: 输入的第一行包含一个整数n,表示给定数字的个数。 第二…...

Linux第90步_异步通知实验
“异步通知”的核心就是信号,由“驱动设备”主动报告给“应用程序”的。 1、添加“EXTI3.c” #include "EXTI3.h" #include <linux/gpio.h> //使能gpio_request(),gpio_free(),gpio_direction_input(), //使能gpio_direction_output(),gpio_get_v…...
elasticdump之python脚本
参考文章目录 elasticdump之shell备份脚本 前言 在企业实际生产环境中,避免不了要对es集群进行迁移、数据备份与恢复,以此来确保数据的可用性及完整性。因此,就涉及到了数据备份与恢复。本章主要以elasticdumppython为主,实现es集群索引备…...

Hystrix应用:如何在Spring Boot中使用Hystrix?
Hystrix应用:如何在Spring Boot中使用Hystrix? 引言 在微服务架构的发展过程中,面对复杂的服务依赖和不可预见的系统故障,如何提升系统的容错能力成为了一个非常急迫且重要的能力。 由 Netflix(网飞)公司…...
js的常用方法
js的常用方法已经使用过的实例 JavaScript有许多基本方法,这些方法可用于执行各种操作,包括字符串操作、数组操作、数学运算等。以下是一些常用的JavaScript基本方法及简单示例: 一、字符串方法 1、toUpperCase():将字符串转换为…...

基于SpringBoot实现的在线拍卖系统
系统开发环境 编程语言:Java数据库:MySQL容器:Tomcat工具:IDEA/Ecilpse、Navicat、Maven 系统实现 管理员功能模块 首页 修改密码 用户管理 商品类型管理 拍卖商品 竞拍公告 轮播图 历史竞拍管理 竞拍订单管理 留言板管理 用户…...

React 组件生命周期对比:Class vs. 函数式
在 React 中,Class 组件和函数式组件的生命周期存在一些差异。通过对 React 中 Class 组件和函数式组件的生命周期进行对比,详细探讨了它们在设计哲学、生命周期管理和开发技巧上的异同。全面了解 React 中两种组件类型的生命周期特点,以及如…...

Ubuntu去除烦人的顶部【活动】按钮
文章目录 一、需求说明二、打开 extensions 网站三、安装 GNOME Shell 插件四、安装本地连接器五、安装 Hide Activities Button 插件六、最终效果七、卸载本地连接器命令参考 本文所使用的 Ubuntu 系统版本是 Ubuntu 22.04 ! 一、需求说明 使用 Ubuntu 的过程中,屏…...

Vue2(十五):replace属性、编程式路由导航、缓存路由组件、路由组件独有钩子、路由守卫、history与hash
一、router-link的replace属性 1、作用:控制路由跳转时操作浏览器历史记录的模式 2、浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push 3、如何开启repla…...

智慧污水井物联网远程监控案例
智慧污水井物联网远程监控案例 在当今数字化转型的浪潮中,智慧水务已成为城市基础设施建设的重要组成部分。其中,基于物联网技术的智慧污水井远程监控系统以其高效、精准、实时的特性,在提升污水处理效能、保障城市水环境安全、实现精细化管…...

程序员Java.vue,python前端后端爬虫开发资源分享
bat面试资料 bat面试题汇总 提取码:724z 更多资料...
PCL:基于法线微分分割
1.介绍 在三维点云处理中,法线微分分割(Difference of Normals,简称DoN)是一种常用的分割方法,用于将点云中的物体或者场景进行分割成不同的部分或者簇。通过计算点云中每个点的法线向量,以及法线向量的变化率(差异),可以有效地分割出具有明显形状差异的部分,从而实现…...

生产事故:线程管理不善诱发P0故障
背景 处于业务诉求,需要建立一个统一的调度平台,最终是基于 Dolphinscheduler 的 V1.3.6 版本去做二次开发。在平台调研建立时,这个版本是最新的版本 命运之轮开始转动 事故 表象 上班后业务部门反馈工作流阻塞,登录系统发现大…...
WPF —— GDI画板
定义绘制对象 Graphics g; 起始点坐标 Point start; 画笔颜色 Color c1 Color.Black; 是否开始绘制 当flagtrue开始绘制,结束绘 private void Form1_MouseDown(object sender, MouseEventArgs e) {if (e.Button MouseButtons.Left) //点击了鼠标左键{start …...
C++:基于范围的for循环
使用迭代器遍历容器在遍历的过程中需要给出容器的两端:开头(begin)和结尾(end),因为这种遍历方式不是基于范围来设计的。在基于范围的for循环中,不需要再传递容器的两端,循环会自动以…...

引领智能互联时代,紫光展锐赋能百业创新发展
随着5G技术的快速发展,各行各业对通信技术的需求也在不断升级。紫光展锐持续深耕5G垂直行业,不断推进5G标准演进,从R15到R16,再到R17,展锐携手生态合作伙伴,不断推出创新性解决方案,在5G RedCap…...

lv_micropython to download and building
想要在ESP32-C3使用Micropython开发GUI,所以需要编译lv_micropython,当前github上的版本是9.1.0。 一、开发环境 因为编译lv_micropython需要在linux系统下,但是我的电脑是windows系统,所以我在windows系统上安装了VMware虚拟机&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...

npm安装electron下载太慢,导致报错
npm安装electron下载太慢,导致报错 背景 想学习electron框架做个桌面应用,卡在了安装依赖(无语了)。。。一开始以为node版本或者npm版本太低问题,调整版本后还是报错。偶尔执行install命令后,可以开始下载…...