feat(ops): U4 后端镜像瘦身 282MB→107MB (62%降幅)
- 移除 git/docker-cli/docker-cli-buildx (~100MB) 改为懒加载 - PipelineHandler 注入 ToolInstaller, runCheckout/runImageBuild 调 EnsureAvailable - UpgradeTools 自动升级 DB 中 git/docker-cli preinstall→lazy - 仅内置 linux-amd64 agent (~12MB节省), arm64/darwin 通过下载API - kubectl 改用 install-kubectl.sh 下载 stripped 版本 - .dockerignore 排除 backend/kubectl 60MB 二进制 - Dockerfile.embed + backend/Dockerfile 同步更新 - 17/17 集成测试通过
This commit is contained in:
1 parent
8dd5a07b70
commit
c624ca5b4a
11 files changed
+175
-47
No files matched your search
+3
-5
@@ -81,10 +81,10 @@ FROM alpine:3.20
|
||||
ARG TARGETARCH
|
||||
ARG KUBECTL_VERSION=v1.32.2
|
||||
|
||||
# 安装运行时依赖(核心最小集,重型工具改为懒加载)// Logan.Li
|
||||
# 安装运行时依赖(U4 镜像瘦身 — 核心最小集, git/docker-cli 改为懒加载)// Logan.Li
|
||||
COPY scripts/setup-alpine-mirrors.sh scripts/install-kubectl.sh /tmp/
|
||||
RUN chmod +x /tmp/setup-alpine-mirrors.sh && /tmp/setup-alpine-mirrors.sh && \
|
||||
apk add --no-cache ca-certificates tzdata bash curl git docker-cli docker-cli-buildx && \
|
||||
apk add --no-cache ca-certificates tzdata bash curl && \
|
||||
chmod +x /tmp/install-kubectl.sh && \
|
||||
TARGET_OS=linux TARGET_ARCH="${TARGETARCH}" KUBECTL_VERSION="${KUBECTL_VERSION}" \
|
||||
/tmp/install-kubectl.sh /usr/local/bin/kubectl && \
|
||||
@@ -106,10 +106,8 @@ COPY --from=builder /app/aiops .
|
||||
# 创建运行时目录(agent 二进制 + 安装脚本)
|
||||
RUN mkdir -p /app/agent/bin /app/agent/deploy
|
||||
|
||||
# 复制 agent 二进制(三个平台)
|
||||
# 复制 agent 二进制(U4: 仅 linux-amd64 内置, arm64/darwin 通过下载 API 提供)// Logan.Li
|
||||
COPY --from=agent-builder /agent/bin/aiops-agent-linux-amd64 /app/agent/bin/
|
||||
COPY --from=agent-builder /agent/bin/aiops-agent-linux-arm64 /app/agent/bin/
|
||||
COPY --from=agent-builder /agent/bin/aiops-agent-darwin-arm64 /app/agent/bin/
|
||||
|
||||
# 复制 agent 安装脚本和 systemd service 模板
|
||||
COPY agent/deploy/install.sh /app/agent/deploy/
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"ezops/model"
|
||||
"ezops/middleware"
|
||||
ezredis "ezops/pkg/redis"
|
||||
"ezops/pkg/toolinstaller"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
@@ -53,13 +54,14 @@ func validateCode(db *gorm.DB, code string, excludeID uint) string {
|
||||
|
||||
// PipelineHandler 流水线管理器
|
||||
type PipelineHandler struct {
|
||||
db *gorm.DB
|
||||
cache ezredis.Cache
|
||||
db *gorm.DB
|
||||
cache ezredis.Cache
|
||||
toolInstaller *toolinstaller.ToolInstaller
|
||||
}
|
||||
|
||||
// NewPipelineHandler 创建流水线处理器
|
||||
func NewPipelineHandler(db *gorm.DB, cache ezredis.Cache) *PipelineHandler {
|
||||
return &PipelineHandler{db: db, cache: cache}
|
||||
func NewPipelineHandler(db *gorm.DB, cache ezredis.Cache, ti *toolinstaller.ToolInstaller) *PipelineHandler {
|
||||
return &PipelineHandler{db: db, cache: cache, toolInstaller: ti}
|
||||
}
|
||||
|
||||
// PipelineListItem 列表项(含最近一次运行摘要)// Logan.Li
|
||||
|
||||
@@ -222,6 +222,13 @@ func (h *PipelineHandler) runCheckout(url, branch, workspace string, logFn func(
|
||||
}
|
||||
logFn("info", "代码检出", "> Git 拉取 "+url+" (分支: "+branch+")")
|
||||
|
||||
// U4: 确保工具可用(slim 镜像模式下 git 为懒加载)// Logan.Li
|
||||
if h.toolInstaller != nil {
|
||||
if err := h.toolInstaller.EnsureAvailable("git"); err != nil {
|
||||
return fmt.Errorf("git 不可用(安装失败): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("git", "clone", "--depth", "1", "-b", branch, url, workspace)
|
||||
output, err := cmd.CombinedOutput()
|
||||
// 流式输出到日志
|
||||
@@ -429,6 +436,14 @@ func (h *PipelineHandler) runDockerBuild(workspace string, pipeline model.Pipeli
|
||||
}
|
||||
|
||||
logFn("info", "镜像打包", fmt.Sprintf(">>> Docker 构建 (dockerfile: %s)", dfPath))
|
||||
|
||||
// U4: 确保 Docker CLI 可用(slim 镜像模式下 docker-cli 为懒加载)// Logan.Li
|
||||
if h.toolInstaller != nil {
|
||||
if err := h.toolInstaller.EnsureAvailable("docker-cli"); err != nil {
|
||||
return fmt.Errorf("docker 不可用(安装失败): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("docker", "build", "-t", fullImage, "-f", dfPath, ".")
|
||||
cmd.Dir = buildDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
||||
@@ -191,29 +191,31 @@ echo "[Node.js] Installed: $(node --version) / npm $(npm --version)"
|
||||
`,
|
||||
SortOrder: 4,
|
||||
},
|
||||
// ──── Git — 版本控制(预装)// Logan.Li ────
|
||||
// ──── Git — 版本控制(懒加载, U4 镜像瘦身)// Logan.Li ────
|
||||
{
|
||||
Name: "git",
|
||||
DisplayName: "Git",
|
||||
Description: "版本控制工具,流水线代码拉取使用",
|
||||
Category: "build",
|
||||
InstallMethod: ToolPreinstall,
|
||||
BinaryName: "git",
|
||||
InstallPath: "/usr/bin/git",
|
||||
CheckCommand: "git --version 2>/dev/null",
|
||||
SortOrder: 5,
|
||||
Name: "git",
|
||||
DisplayName: "Git",
|
||||
Description: "版本控制工具,流水线代码拉取使用(首次使用自动安装)",
|
||||
Category: "build",
|
||||
InstallMethod: ToolLazy,
|
||||
BinaryName: "git",
|
||||
InstallPath: "/usr/bin/git",
|
||||
CheckCommand: "git --version 2>/dev/null",
|
||||
InstallScript: `apk add --no-cache git`,
|
||||
SortOrder: 5,
|
||||
},
|
||||
// ──── Docker CLI — 容器构建(预装)// Logan.Li ────
|
||||
// ──── Docker CLI — 容器构建(懒加载, U4 镜像瘦身)// Logan.Li ────
|
||||
{
|
||||
Name: "docker-cli",
|
||||
DisplayName: "Docker CLI",
|
||||
Description: "Docker 命令行工具,流水线镜像构建/推送使用",
|
||||
Category: "deploy",
|
||||
InstallMethod: ToolPreinstall,
|
||||
BinaryName: "docker",
|
||||
InstallPath: "/usr/bin/docker",
|
||||
CheckCommand: "docker --version 2>/dev/null",
|
||||
SortOrder: 6,
|
||||
Name: "docker-cli",
|
||||
DisplayName: "Docker CLI",
|
||||
Description: "Docker 命令行工具,流水线镜像构建/推送使用(首次使用自动安装)",
|
||||
Category: "deploy",
|
||||
InstallMethod: ToolLazy,
|
||||
BinaryName: "docker",
|
||||
InstallPath: "/usr/bin/docker",
|
||||
CheckCommand: "docker --version 2>/dev/null",
|
||||
InstallScript: `apk add --no-cache docker-cli`,
|
||||
SortOrder: 6,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -327,6 +327,8 @@ func (ti *ToolInstaller) SeedTools() {
|
||||
var count int64
|
||||
ti.db.Model(&model.DeployTool{}).Count(&count)
|
||||
if count > 0 {
|
||||
// U4: 即使已有数据也升级工具配置(git/docker-cli 从 preinstall→lazy)
|
||||
ti.UpgradeTools()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -351,4 +353,44 @@ func (ti *ToolInstaller) SeedTools() {
|
||||
} else {
|
||||
log.Printf("[ToolInstaller] Seeded %d tools", len(tools))
|
||||
}
|
||||
|
||||
// U4: 新种子也执行升级
|
||||
ti.UpgradeTools()
|
||||
}
|
||||
|
||||
// UpgradeTools updates existing tool configs to match latest predefined definitions.
|
||||
// U4: git/docker-cli 从 preinstall 迁移到 lazy(镜像瘦身)。
|
||||
func (ti *ToolInstaller) UpgradeTools() {
|
||||
upgrades := map[string]struct {
|
||||
installMethod model.ToolInstallMethod
|
||||
installScript string
|
||||
description string
|
||||
}{
|
||||
"git": {
|
||||
installMethod: model.ToolLazy,
|
||||
installScript: "apk add --no-cache git",
|
||||
description: "版本控制工具,流水线代码拉取使用(首次使用自动安装)",
|
||||
},
|
||||
"docker-cli": {
|
||||
installMethod: model.ToolLazy,
|
||||
installScript: "apk add --no-cache docker-cli",
|
||||
description: "Docker 命令行工具,流水线镜像构建/推送使用(首次使用自动安装)",
|
||||
},
|
||||
}
|
||||
|
||||
for name, up := range upgrades {
|
||||
var tool model.DeployTool
|
||||
if err := ti.db.Where("name = ?", name).First(&tool).Error; err != nil {
|
||||
continue // tool not in DB, skip
|
||||
}
|
||||
if tool.InstallMethod == up.installMethod && tool.InstallScript == up.installScript {
|
||||
continue // already up to date
|
||||
}
|
||||
log.Printf("[ToolInstaller] U4 upgrade: %s %s→%s", name, tool.InstallMethod, up.installMethod)
|
||||
ti.db.Model(&model.DeployTool{}).Where("name = ?", name).Updates(map[string]interface{}{
|
||||
"install_method": up.installMethod,
|
||||
"install_script": up.installScript,
|
||||
"description": up.description,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ func Register(r *gin.Engine, db *gorm.DB, log *zap.Logger, cfg *config.Config, c
|
||||
api.POST("/auth/register", authHandler.Register)
|
||||
|
||||
// Webhook 触发路由(无需 JWT,由 Webhook Token 签名验证)
|
||||
pipelineHandler := controller.NewPipelineHandler(db, redisCache)
|
||||
pipelineHandler := controller.NewPipelineHandler(db, redisCache, ti)
|
||||
webhookGroup := api.Group("/webhook")
|
||||
{
|
||||
webhookGroup.POST("/job/:jobName", pipelineHandler.WebhookTrigger)
|
||||
|
||||
Reference in new issue
Block a user