feat: 添加了 imager 工具 package

refactor: 将  images 的获取分散到各个组件里面
This commit is contained in:
zhaoyupeng
2025-12-29 23:01:42 +08:00
parent c53c15fa8c
commit 0bcb138fd5
20 changed files with 1519 additions and 56 deletions

View File

@@ -50,6 +50,7 @@ func makeCmd() *cobra.Command {
_cmd.PersistentFlags().StringVar(&opt.Cfg.Make.Dir, "dir", "/root/hsv2-installation", "make base directory")
_cmd.AddCommand(
makecmd.ALL(),
makecmd.Images(),
makecmd.Binaries(),
makecmd.Flannel(),
@@ -60,6 +61,7 @@ func makeCmd() *cobra.Command {
makecmd.EMQX(),
makecmd.Minio(),
makecmd.Yosguard(),
makecmd.Registry(),
makecmd.LessDNS(),
makecmd.HSNet(),
makecmd.ConfigMap(),

130
internal/cmd/makecmd/all.go Normal file
View File

@@ -0,0 +1,130 @@
package makecmd
import (
"github.com/spf13/cobra"
"yizhisec.com/hsv2/forge/internal/controller/maker"
"yizhisec.com/hsv2/forge/internal/opt"
)
func ALL() *cobra.Command {
var (
_workdir string
)
_cmd := &cobra.Command{
Use: "all",
Short: "Make all",
RunE: func(cmd *cobra.Command, args []string) error {
var (
err error
mk = maker.NewMaker(_workdir)
)
if err = mk.Images(cmd.Context()); err != nil {
return err
}
if err = mk.Binary(cmd.Context()); err != nil {
return err
}
if err = mk.Registry(cmd.Context(), "50Gi"); err != nil {
return err
}
if err = mk.Flannel(cmd.Context(), "host-gw"); err != nil {
return err
}
if err = mk.Longhorn(cmd.Context(), 2); err != nil {
return err
}
if err = mk.MySQL(cmd.Context()); err != nil {
return err
}
if err = mk.Redis(cmd.Context()); err != nil {
return err
}
if err = mk.Elastic(cmd.Context()); err != nil {
return err
}
if err = mk.EMQX(cmd.Context()); err != nil {
return err
}
if err = mk.Minio(cmd.Context(), "100Gi"); err != nil {
return err
}
if err = mk.Yosguard(cmd.Context()); err != nil {
return err
}
if err = mk.LessDNS(cmd.Context()); err != nil {
return err
}
if err = mk.HSNet(cmd.Context()); err != nil {
return err
}
if err = mk.ConfigMap(cmd.Context()); err != nil {
return err
}
if err = mk.Proxy(cmd.Context()); err != nil {
return err
}
if err = mk.Seafile(cmd.Context()); err != nil {
return err
}
if err = mk.Proxy(cmd.Context()); err != nil {
return err
}
if err = mk.Seafile(cmd.Context()); err != nil {
return err
}
if err = mk.AppOEM(cmd.Context(), "standard", 2); err != nil {
return err
}
if err = mk.AppUser(cmd.Context(), 2); err != nil {
return err
}
if err = mk.AppClient(cmd.Context(), 2); err != nil {
return err
}
if err = mk.AppGateway(cmd.Context(), 2); err != nil {
return err
}
if err = mk.AppFront(cmd.Context(), "standard", 2); err != nil {
return err
}
if err = mk.AppMie(cmd.Context(), 2); err != nil {
return err
}
if err = mk.AppNginx(cmd.Context()); err != nil {
return err
}
return nil
},
}
_cmd.PersistentFlags().StringVar(&_workdir, "workdir", opt.DefaultWorkdir, "Work directory")
return _cmd
}

View File

@@ -112,7 +112,7 @@ func appOEM() *cobra.Command {
Short: "Make OEM App",
RunE: func(cmd *cobra.Command, args []string) error {
mk := maker.NewMaker(opt.Cfg.Make.Dir)
return mk.AppOEM(cmd.Context(), replica, vendor)
return mk.AppOEM(cmd.Context(), vendor, replica)
},
}

View File

@@ -1,6 +1,8 @@
package makecmd
import (
"fmt"
"github.com/spf13/cobra"
"yizhisec.com/hsv2/forge/internal/controller/maker"
"yizhisec.com/hsv2/forge/internal/opt"
@@ -10,7 +12,7 @@ func Redis() *cobra.Command {
var (
replicas int
password string
storage string
storage int
)
_cmd := &cobra.Command{
@@ -23,14 +25,14 @@ func Redis() *cobra.Command {
cmd.Context(),
maker.WithRedisReplicaCount(replicas),
maker.WithRedisPassword(password),
maker.WithRedisStorage(storage),
maker.WithRedisStorage(fmt.Sprintf("%dGi")),
)
},
}
_cmd.Flags().IntVar(&replicas, "replica-count", 2, "Redis 副本数")
_cmd.Flags().StringVar(&password, "password", "", "Redis 密码")
_cmd.Flags().StringVar(&storage, "storage-size", "5Gi", "Redis 存储大小(如: 5Gi)")
_cmd.Flags().IntVar(&storage, "storage-size", 5, "Redis 存储大小(单位Gi)如: 5")
return _cmd
}

View File

@@ -0,0 +1,28 @@
package makecmd
import (
"fmt"
"github.com/spf13/cobra"
"yizhisec.com/hsv2/forge/internal/controller/maker"
"yizhisec.com/hsv2/forge/internal/opt"
)
func Registry() *cobra.Command {
var (
size int
)
_cmd := &cobra.Command{
Use: "registry",
Short: "Make registry dependency",
RunE: func(cmd *cobra.Command, args []string) error {
mk := maker.NewMaker(opt.Cfg.Make.Dir)
return mk.Registry(cmd.Context(), fmt.Sprintf("%dGi", size))
},
}
_cmd.Flags().IntVar(&size, "storage-size", 50, "Redis 存储大小(单位Gi)如: 100")
return _cmd
}

View File

@@ -0,0 +1,5 @@
package installer
func (i *installer) Redis() error {
return nil
}

View File

@@ -13,7 +13,7 @@ import (
"yizhisec.com/hsv2/forge/pkg/resource"
)
func (m *maker) AppOEM(ctx context.Context, replica int, vendor string) error {
func (m *maker) AppOEM(ctx context.Context, vendor string, replica int) error {
const (
_nginx = `user root;
worker_processes auto;

View File

@@ -7,6 +7,7 @@ import (
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/pkg/model"
"yizhisec.com/hsv2/forge/pkg/resource"
)
@@ -33,6 +34,27 @@ func (m *maker) Flannel(ctx context.Context, mode string) error {
return err
}
var images = []*model.Image{
{Name: "ghcr.io/flannel-io/flannel:v0.27.4", Fallback: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/flannel-io/flannel:v0.27.4", Save: "flannel.tar"},
{Name: "ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1", Fallback: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1", Save: "flannel-cni-plugin.tar"},
}
logger.Debug("MakeFlannel: 开始获取镜像...")
for _, image := range images {
opts := []ImageOpt{
WithImageFallback(image.Fallback),
WithImageSave(filepath.Join(location, image.Save)),
WithImageForcePull(image.Force),
}
if err := m.Image(ctx, image.Name, opts...); err != nil {
logger.Error("❌ MakeFlannel: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
logger.Debug("❌ MakeFlannel: 获取镜像失败: %s, %v", image.Name, err)
return err
}
}
logger.Debug("MakeFlannel: 获取镜像成功!!!")
logger.Info("✅ 构建 flannel 成功!!!")
return nil

View File

@@ -46,10 +46,8 @@ ExecStart=/usr/local/bin/k0s ctr -n hs-net run \
# --cgroup host \
# --env RUSTFLAGS="-C target-cpu=nehalem" \
# 重启策略
Restart=on-failure
Restart=always
RestartSec=5s
StartLimitInterval=60s
StartLimitBurst=5
# 资源限制(按需调整)
MemoryLimit=2G

View File

@@ -119,21 +119,6 @@ func (m *maker) Images(ctx context.Context) error {
{Name: "quay.io/k0sproject/metrics-server:v0.7.2-0", Fallback: "", Save: "k0s.metrics-server.tar"},
{Name: "quay.io/k0sproject/pause:3.10.1", Fallback: "", Save: "k0s.pause.tar"},
{Name: "ghcr.io/flannel-io/flannel:v0.27.4", Fallback: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/flannel-io/flannel:v0.27.4", Save: "flannel.tar"},
{Name: "ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1", Fallback: "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/ghcr.io/flannel-io/flannel-cni-plugin:v1.8.0-flannel1", Save: "flannel-cni-plugin.tar"},
{Name: "docker.io/longhornio/longhorn-engine:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-engine:v1.10.0", Save: "longhorn.longhorn-engine.tar"},
{Name: "docker.io/longhornio/longhorn-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-manager:v1.10.0", Save: "longhorn.longhorn-manager.tar"},
{Name: "docker.io/longhornio/longhorn-instance-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-instance-manager:v1.10.0", Save: "longhorn.longhorn-instance-manager.tar"},
{Name: "docker.io/longhornio/longhorn-share-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-share-manager:v1.10.0", Save: "longhorn.longhorn-share-manager.tar"},
{Name: "docker.io/longhornio/longhorn-ui:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-ui:v1.10.0", Save: "longhorn.longhorn-ui.tar"},
{Name: "docker.io/longhornio/csi-snapshotter:v8.3.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-snapshotter:v8.3.0-20250826", Save: "longhorn.csi-snapshotter.tar"},
{Name: "docker.io/longhornio/csi-resizer:v1.14.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-resizer:v1.14.0-20250826", Save: "longhorn.csi-resizer.tar"},
{Name: "docker.io/longhornio/csi-provisioner:v5.3.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-provisioner:v5.3.0-20250826", Save: "longhorn.csi-provisioner.tar"},
{Name: "docker.io/longhornio/livenessprobe:v2.16.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/livenessprobe:v2.16.0-20250826", Save: "longhorn.livenessprobe.tar"},
{Name: "docker.io/longhornio/csi-node-driver-registrar:v2.14.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-node-driver-registrar:v2.14.0-20250826", Save: "longhorn.csi-node-driver-registrar.tar"},
{Name: "docker.io/longhornio/csi-attacher:v4.9.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-attacher:v4.9.0-20250826", Save: "longhorn.csi-attacher.tar"},
{Name: "hub.yizhisec.com/external/alpine:3.22.2", Fallback: "", Save: "alpine.tar", Force: true},
{Name: "hub.yizhisec.com/external/nginx:1.29.1-alpine3.22", Fallback: "", Save: "nginx.1.29.1-alpine3.22.tar"},

View File

@@ -8,6 +8,7 @@ import (
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/pkg/downloader"
"yizhisec.com/hsv2/forge/pkg/model"
)
func (m *maker) Longhorn(ctx context.Context, replica int) error {
@@ -23,16 +24,16 @@ persistence:
)
var (
err error
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/longhorn-1.10.0.tgz"
longhornDir = filepath.Join(m.workdir, "dependency", "longhorn")
chartFile = filepath.Join(longhornDir, "longhorn-1.10.0.tgz")
valuesFile = filepath.Join(longhornDir, "values.yaml")
err error
chartURL = "https://artifactory.yizhisec.com:443/artifactory/filestore/hsv3/charts/longhorn-1.10.0.tgz"
location = filepath.Join(m.workdir, "dependency", "longhorn")
chartFile = filepath.Join(location, "longhorn-1.10.0.tgz")
valuesFile = filepath.Join(location, "values.yaml")
)
logger.Info("☑️ 开始准备 Longhorn 资源...")
logger.Debug("下载地址: %s", chartURL)
logger.Debug("目标目录: %s", longhornDir)
logger.Debug("目标目录: %s", location)
if err = os.MkdirAll(filepath.Join(m.workdir, "dependency", "longhorn"), 0755); err != nil {
return err
@@ -57,6 +58,36 @@ persistence:
return err
}
var images = []*model.Image{
{Name: "docker.io/longhornio/longhorn-engine:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-engine:v1.10.0", Save: "longhorn.longhorn-engine.tar"},
{Name: "docker.io/longhornio/longhorn-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-manager:v1.10.0", Save: "longhorn.longhorn-manager.tar"},
{Name: "docker.io/longhornio/longhorn-instance-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-instance-manager:v1.10.0", Save: "longhorn.longhorn-instance-manager.tar"},
{Name: "docker.io/longhornio/longhorn-share-manager:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-share-manager:v1.10.0", Save: "longhorn.longhorn-share-manager.tar"},
{Name: "docker.io/longhornio/longhorn-ui:v1.10.0", Fallback: "docker-mirror.yizhisec.com/longhornio/longhorn-ui:v1.10.0", Save: "longhorn.longhorn-ui.tar"},
{Name: "docker.io/longhornio/csi-snapshotter:v8.3.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-snapshotter:v8.3.0-20250826", Save: "longhorn.csi-snapshotter.tar"},
{Name: "docker.io/longhornio/csi-resizer:v1.14.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-resizer:v1.14.0-20250826", Save: "longhorn.csi-resizer.tar"},
{Name: "docker.io/longhornio/csi-provisioner:v5.3.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-provisioner:v5.3.0-20250826", Save: "longhorn.csi-provisioner.tar"},
{Name: "docker.io/longhornio/livenessprobe:v2.16.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/livenessprobe:v2.16.0-20250826", Save: "longhorn.livenessprobe.tar"},
{Name: "docker.io/longhornio/csi-node-driver-registrar:v2.14.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-node-driver-registrar:v2.14.0-20250826", Save: "longhorn.csi-node-driver-registrar.tar"},
{Name: "docker.io/longhornio/csi-attacher:v4.9.0-20250826", Fallback: "docker-mirror.yizhisec.com/longhornio/csi-attacher:v4.9.0-20250826", Save: "longhorn.csi-attacher.tar"},
}
logger.Debug("MakeLonghorn: 开始获取镜像...")
for _, image := range images {
opts := []ImageOpt{
WithImageFallback(image.Fallback),
WithImageSave(filepath.Join(location, image.Save)),
WithImageForcePull(image.Force),
}
if err := m.Image(ctx, image.Name, opts...); err != nil {
logger.Error("❌ MakeLonghorn: 获取镜像失败: %s, 可以手动获取后重试", image.Name)
logger.Debug("❌ MakeLonghorn: 获取镜像失败: %s, %v", image.Name, err)
return err
}
}
logger.Debug("MakeLonghorn: 获取镜像成功!!!")
logger.Info("✅ 成功创建 longhorn 资源!!!")
return nil

View File

@@ -0,0 +1,73 @@
package maker
import (
"context"
"fmt"
"os"
"path/filepath"
"gitea.loveuer.com/yizhisec/pkg3/logger"
"yizhisec.com/hsv2/forge/pkg/resource"
)
func (m *maker) Registry(ctx context.Context, storage string) error {
const (
_registryToml = `
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = ""
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."10.96.123.45:80"]
endpoint = ["http://10.96.123.45:80"]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."10.96.123.45:80".tls]
insecure_skip_verify = true
[plugins."io.containerd.grpc.v1.cri".registry.configs."10.96.123.45:80".auth]`
)
var (
err error
location = filepath.Join(m.workdir, "dependency", "registry")
imgName = "docker.io/library/registry:2.8.3"
uiImgName = "docker.io/quiq/registry-ui:0.11.0"
imgFallback = "docker-mirror.yizhisec.com/library/registry:2.8.3"
uiImgFallback = "docker-mirror.yizhisec.com/quiq/registry-ui:0.11.0"
)
logger.Info("☑️ 开始创建依赖: registry...")
logger.Debug("☑️ 创建 dir: %s ...", location)
if err = os.MkdirAll(location, 0755); err != nil {
logger.Debug("❌ 创建 dir %s 失败: %v", location, err)
return err
}
yamlFile := filepath.Join(location, "registry.yaml")
content := fmt.Sprintf(resource.YAMLRegistry, storage)
logger.Debug("写入 yaml 文件: %s ...", yamlFile)
if os.WriteFile(yamlFile, []byte(content), 0644); err != nil {
logger.Debug("❌ 写入 yaml 文件 %s 失败: %v", yamlFile, err)
return err
}
logger.Debug("开始准备镜像...")
imgFile := filepath.Join(location, "registry.tar")
if err = m.Image(ctx, imgName, WithImageFallback(imgFallback), WithImageSave(imgFile)); err != nil {
logger.Debug("❌ 准备镜像 %s 失败: %v", imgName, err)
return err
}
imgFile = filepath.Join(location, "registry-ui.tar")
if err = m.Image(ctx, uiImgName, WithImageFallback(uiImgFallback), WithImageSave(imgFile)); err != nil {
logger.Debug("❌ 准备镜像 %s 失败: %v", uiImgName, err)
return err
}
logger.Debug("写入 registry.toml 文件: %s ...", filepath.Join(location, "registry.toml"))
if os.WriteFile(filepath.Join(location, "registry.toml"), []byte(_registryToml), 0644); err != nil {
logger.Debug("❌ 写入 registry.toml 文件 %s 失败: %v", filepath.Join(location, "registry.toml"), err)
return err
}
logger.Info("✅ 创建依赖成功: registry!!!")
return nil
}

View File

@@ -16,32 +16,21 @@ type yosguardOpt struct{}
func (m *maker) Yosguard(ctx context.Context, opts ...YosguardOpt) error {
const (
configTemplate = `
Web:
# default listen in docker0
Host: 172.17.0.1
Port: 7788
UUIDFilePath: /etc/yosguard/uuid
# 心跳间隔: 单位秒,默认为5
HeartbeatDuration: 5
# 控制器 yosguard 地址
_config = `
AsController: true
AsGateway: false
ControllerServer:
Host: dasheng.zhsftech.debug
Port: 443
# True: 作为控制器运行; False: 不作为控制器运行
AsController: true
# True: 作为网关运行; False: 不作为网关运行
AsGateway: false
Port: 443
Database:
SQLite:
DBPath: "/etc/yosguard/db/yosguard.db"
SQLPath: "/etc/yosguard/db/create.sql"`
DBPath: /etc/yosguard/db/yosguard.db
HeartbeatDuration: 5
UUIDFilePath: /etc/yosguard/uuid
Web:
Host: __ip__
Port: 7788
`
systemdService = `
[Unit]
@@ -86,12 +75,12 @@ WantedBy=multi-user.target`
}
logger.Debug("✅ maker.Yosguard: 下载 yosguard 成功, url = %s", binURL)
logger.Debug("☑️ maker.Yosguard: 写入 config_template.yml 文件..., dest = %s", filepath.Join(location, "config_template.yml"))
if err := os.WriteFile(filepath.Join(location, "config_template.yml"), []byte(configTemplate), 0644); err != nil {
logger.Debug("❌ maker.Yosguard: 写入 config_template.yml 失败, dest = %s, err = %v", filepath.Join(location, "config_template.yml"), err)
logger.Debug("☑️ maker.Yosguard: 写入 config.yml 文件..., dest = %s", filepath.Join(location, "config.yml"))
if err := os.WriteFile(filepath.Join(location, "config.yml"), []byte(_config), 0644); err != nil {
logger.Debug("❌ maker.Yosguard: 写入 config.yml 失败, dest = %s, err = %v", filepath.Join(location, "config.yml"), err)
return err
}
logger.Debug("✅ maker.Yosguard: 写入 config_template.yml 文件成功, dest = %s", filepath.Join(location, "config_template.yml"))
logger.Debug("✅ maker.Yosguard: 写入 config.yml 文件成功, dest = %s", filepath.Join(location, "config.yml"))
logger.Debug("☑️ maker.Yosguard: 写入 create.sql 文件..., dest = %s", filepath.Join(location, "create.sql"))
if err := os.WriteFile(filepath.Join(location, "create.sql"), resource.SQLYosguard, 0644); err != nil {

View File

@@ -14,6 +14,10 @@ var (
Cfg = &config{}
)
const (
DefaultWorkdir = "/root/hsv2-installation"
)
var (
StorageSizeReg = regexp.MustCompile(`^\d+(\.\d+)?[EPTGMK]i?$`)
EmailReg = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)