feat(build): kaniko/trivy 与扫描库改用 registry 内的 mirror 副本,定时刷新并在过期时告警

This commit is contained in:
Lemon-miaow committed 2026-09-24 23:25:21 +08:00
1 parent c0643af118
commit bf18712a6c
14 files changed
+426 -82

No files matched your search

+125
View File
@@ -0,0 +1,125 @@
package main
import (
"context"
"errors"
"flag"
"fmt"
"io"
"os"
"os/signal"
"strings"
"syscall"
"time"
"felis.lolicon.best/internal/build"
"felis.lolicon.best/internal/imagepush"
"felis.lolicon.best/internal/registrygate"
)
// defaultBuildToolsStatus is where mirror-build-tools records its last run; the
// watchdog reads it to tell a vulnerability DB that stopped refreshing.
const defaultBuildToolsStatus = "/var/lib/felis/build-tools/status.json"
// cmdMirrorBuildTools copies the build lane's tools (build.Tools: the kaniko and
// trivy images, Trivy's vulnerability and Java DBs) from upstream into the
// platform registry, where build Jobs pull them. deploy/bootstrap.sh runs it at
// install and from felis-build-tools.timer twice a day, which is what keeps the
// DBs fresh; a root shell can run it the same way to refresh now.
//
// It writes as the platform principal through the node's loopback hostPort, the
// same way the installer pushes, reading the token from the environment or from
// /etc/felis/secrets.env.
func cmdMirrorBuildTools(args []string, stdout, stderr io.Writer) int {
fs := flag.NewFlagSet("mirror-build-tools", flag.ContinueOnError)
fs.SetOutput(stderr)
endpoint := fs.String("endpoint", "127.0.0.1:5000", "host[:port] of the registry to write to (plain HTTP)")
only := fs.String("only", "", "comma-separated tool names to copy (default: all of "+toolNames()+")")
status := fs.String("status", defaultBuildToolsStatus, `file to record the run in ("" records nothing)`)
secrets := fs.String("secrets-env", "/etc/felis/secrets.env", "installer secrets file holding REGISTRY_PLATFORM_TOKEN, read when FELIS_REGISTRY_PASSWORD is unset")
platformFlag := fs.String("platform", "", "os/arch of the images to copy (default: this machine's)")
if err := fs.Parse(args); err != nil {
if errors.Is(err, flag.ErrHelp) {
return 0
}
return 2
}
tools, err := selectTools(*only)
if err != nil {
fmt.Fprintf(stderr, "felis mirror-build-tools: %v\n", err)
return 2
}
if err := loadEnvFile(*secrets); err != nil {
fmt.Fprintf(stderr, "felis mirror-build-tools: read %s: %v\n", *secrets, err)
return 1
}
user, pass := os.Getenv("FELIS_REGISTRY_USERNAME"), os.Getenv("FELIS_REGISTRY_PASSWORD")
if pass == "" {
user, pass = registrygate.PrincipalPlatform, os.Getenv("REGISTRY_PLATFORM_TOKEN")
}
if pass == "" {
fmt.Fprintln(stderr, "felis mirror-build-tools: no registry credential: set FELIS_REGISTRY_PASSWORD or run as root on the node (REGISTRY_PLATFORM_TOKEN in /etc/felis/secrets.env)")
return 2
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
p := &imagepush.Pusher{Scheme: "http", Username: user, Password: pass, Log: stdout}
src := &imagepush.Source{Platform: *platformFlag}
started := time.Now()
var failed []string
for _, t := range tools {
dst := strings.TrimSuffix(*endpoint, "/") + "/" + t.Mirror
if _, err := p.Mirror(ctx, src, t.Source, dst); err != nil {
fmt.Fprintf(stderr, "felis mirror-build-tools: %s: %v\n", t.Name, err)
failed = append(failed, t.Name+": "+err.Error())
}
}
if *status != "" {
st, err := imagepush.ReadMirrorStatus(*status)
if err != nil || st == nil {
st = &imagepush.MirrorStatus{}
}
st.LastAttempt = started
st.LastError = strings.Join(failed, "; ")
if len(failed) == 0 {
st.LastSuccess = started
}
if err := imagepush.WriteMirrorStatus(*status, *st); err != nil {
fmt.Fprintf(stderr, "felis mirror-build-tools: record %s: %v\n", *status, err)
}
}
if len(failed) > 0 {
return 1
}
return 0
}
func toolNames() string {
var names []string
for _, t := range build.Tools {
names = append(names, t.Name)
}
return strings.Join(names, ",")
}
func selectTools(only string) ([]build.Tool, error) {
if only == "" {
return build.Tools, nil
}
var out []build.Tool
for _, name := range strings.Split(only, ",") {
name = strings.TrimSpace(name)
found := false
for _, t := range build.Tools {
if t.Name == name {
out = append(out, t)
found = true
}
}
if !found {
return nil, fmt.Errorf("unknown tool %q (known: %s)", name, toolNames())
}
}
return out, nil
}