fix(updater): 复用原 Compose 项目名并保护非 Compose 部署
This commit is contained in:
@@ -8,6 +8,10 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- **示例页面新增独立升级验证区块**:页面增加「本次升级验证」高亮区块,显示 `v1.3.7`,验证标识更新为 `v1.3.7-example-page`,用于直观确认升级后的前端资源已切换
|
||||
|
||||
### 修复
|
||||
|
||||
- **复用原 Compose 项目名重建容器**:updater 在通过 helper 容器执行 `docker compose` 时,先从现有 `fonu` 容器读取 `com.docker.compose.project` 标签,并显式传入同一个项目名,避免 Compose 将现有容器视为另一个项目后重新创建网络、数据卷并撞上 `/fonu` 容器名冲突。现有容器不是 Compose 管理时,updater 会拒绝升级并提示按 Compose 方式重新部署,避免误建空数据卷
|
||||
|
||||
### 变更
|
||||
|
||||
- 版本号提升到 1.3.7;`web/package.json` 与 `web/package-lock.json` 同步对齐
|
||||
|
||||
@@ -21,6 +21,7 @@ func main() {
|
||||
Branch: envOr("FONU_UPDATE_BRANCH", "main"),
|
||||
AppURL: envOr("FONU_UPDATE_APP_URL", "http://fonu:6893"),
|
||||
HostProjectDir: envOr("FONU_UPDATE_HOST_DIR", ""),
|
||||
ProjectName: envOr("FONU_UPDATE_PROJECT_NAME", ""),
|
||||
SelfImage: envOr("FONU_UPDATE_SELF_IMAGE", ""),
|
||||
DockerSocket: envOr("FONU_UPDATE_DOCKER_SOCK", "/var/run/docker.sock"),
|
||||
}, nil)
|
||||
|
||||
@@ -82,6 +82,7 @@ services:
|
||||
FONU_UPDATE_BRANCH: main
|
||||
FONU_UPDATE_APP_URL: http://fonu:6893
|
||||
FONU_UPDATE_HOST_DIR: ${FONU_UPDATE_HOST_DIR:-}
|
||||
FONU_UPDATE_PROJECT_NAME: ${FONU_UPDATE_PROJECT_NAME:-fonu}
|
||||
FONU_UPDATE_SELF_IMAGE: fonu-updater:${FONU_VERSION:-local}
|
||||
FONU_UPDATE_DOCKER_SOCK: ${DOCKER_SOCK:-/var/run/docker.sock}
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
|
||||
@@ -64,6 +64,7 @@ services:
|
||||
FONU_UPDATE_MODE: local
|
||||
FONU_UPDATE_APP_URL: http://fonu:6893
|
||||
FONU_UPDATE_HOST_DIR: ${FONU_UPDATE_HOST_DIR:-}
|
||||
FONU_UPDATE_PROJECT_NAME: ${FONU_UPDATE_PROJECT_NAME:-fonu}
|
||||
FONU_UPDATE_SELF_IMAGE: fonu-updater:${FONU_VERSION:-local}
|
||||
FONU_UPDATE_DOCKER_SOCK: ${DOCKER_SOCK:-/var/run/docker.sock}
|
||||
TZ: ${TZ:-Asia/Shanghai}
|
||||
|
||||
@@ -182,6 +182,12 @@ docker compose -f /实际/的/Compose/目录/docker-compose.hub.yml up -d --buil
|
||||
|
||||
状态接口会明确提示 Compose 文件缺失,修复挂载或设置覆盖后按钮才会重新显示。
|
||||
|
||||
### 报 `container name "/fonu" is already in use`
|
||||
|
||||
这表示 Compose 没有识别到当前容器所属的原项目,可能把升级当成新项目并尝试新建网络与数据卷。v1.3.7 的更新版 updater 会读取现有容器的 `com.docker.compose.project` 标签,并显式复用原项目名。
|
||||
|
||||
如果现有 `fonu` 容器不是由 Compose 管理,updater 会拒绝升级,避免新建 `fonu_fonu-data` 等空数据卷。应先按 Compose 方式重新部署,再使用一键升级。
|
||||
|
||||
### `docker-compose.hub.yml` 模式无法读取远端版本
|
||||
|
||||
检查 sidecar 容器内是否可以访问 Git 仓库:
|
||||
|
||||
@@ -323,7 +323,7 @@ func (s *Server) compose(ctx context.Context, version string, args ...string) (s
|
||||
if plan.helper {
|
||||
return s.composeViaHelper(ctx, plan, version, args...)
|
||||
}
|
||||
fullArgs := append([]string{"compose", "-f", plan.containerCompose}, args...)
|
||||
fullArgs := append([]string{"compose", "--project-name", plan.projectName, "-f", plan.containerCompose}, args...)
|
||||
env := []string{"FONU_VERSION=" + version}
|
||||
return runCommand(ctx, s.cfg.ProjectDir, env, "docker", fullArgs...)
|
||||
}
|
||||
@@ -340,7 +340,7 @@ func (s *Server) composeViaHelper(ctx context.Context, plan composePlan, version
|
||||
"-w", "/workspace",
|
||||
"-e", "FONU_VERSION=" + version,
|
||||
image,
|
||||
"compose", "-f", plan.helperComposePath,
|
||||
"compose", "--project-name", plan.projectName, "-f", plan.helperComposePath,
|
||||
}
|
||||
helperArgs = append(helperArgs, args...)
|
||||
return runCommand(ctx, "", nil, "docker", helperArgs...)
|
||||
|
||||
@@ -31,6 +31,7 @@ type Config struct {
|
||||
Branch string
|
||||
AppURL string
|
||||
HostProjectDir string
|
||||
ProjectName string
|
||||
SelfImage string
|
||||
DockerSocket string
|
||||
BuildTimeout time.Duration
|
||||
@@ -49,6 +50,7 @@ type Server struct {
|
||||
|
||||
type composePlan struct {
|
||||
helper bool
|
||||
projectName string
|
||||
containerCompose string
|
||||
hostProjectDir string
|
||||
hostComposePath string
|
||||
@@ -83,6 +85,7 @@ func NewServer(cfg Config, logger *slog.Logger) (*Server, error) {
|
||||
cfg.DockerSocket = "/var/run/docker.sock"
|
||||
}
|
||||
cfg.HostProjectDir = strings.TrimSpace(cfg.HostProjectDir)
|
||||
cfg.ProjectName = strings.TrimSpace(cfg.ProjectName)
|
||||
cfg.SelfImage = strings.TrimSpace(cfg.SelfImage)
|
||||
if cfg.BuildTimeout <= 0 {
|
||||
cfg.BuildTimeout = 30 * time.Minute
|
||||
@@ -184,9 +187,13 @@ func (s *Server) ensureComposeFile(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (s *Server) resolveComposePlan(ctx context.Context) (composePlan, error) {
|
||||
projectName, err := s.composeProjectName(ctx)
|
||||
if err != nil {
|
||||
return composePlan{}, err
|
||||
}
|
||||
info, err := os.Stat(s.composePath)
|
||||
if err == nil && !info.IsDir() {
|
||||
return composePlan{containerCompose: s.composePath}, nil
|
||||
return composePlan{projectName: projectName, containerCompose: s.composePath}, nil
|
||||
}
|
||||
if err == nil && info.IsDir() {
|
||||
return composePlan{}, fmt.Errorf("Compose 路径是目录而不是文件:%s", s.composePath)
|
||||
@@ -197,6 +204,7 @@ func (s *Server) resolveComposePlan(ctx context.Context) (composePlan, error) {
|
||||
if pathErr == nil {
|
||||
return composePlan{
|
||||
helper: true,
|
||||
projectName: projectName,
|
||||
hostProjectDir: hostDir,
|
||||
hostComposePath: hostComposePath,
|
||||
helperComposePath: helperPath,
|
||||
@@ -206,6 +214,21 @@ func (s *Server) resolveComposePlan(ctx context.Context) (composePlan, error) {
|
||||
return composePlan{}, fmt.Errorf("找不到 Compose 文件 %s,且无法自动定位宿主机目录;请设置 FONU_UPDATE_HOST_DIR", s.composePath)
|
||||
}
|
||||
|
||||
func (s *Server) composeProjectName(ctx context.Context) (string, error) {
|
||||
projectName, err := s.dockerLabel(ctx, "com.docker.compose.project")
|
||||
projectName = strings.TrimSpace(projectName)
|
||||
if projectName != "" {
|
||||
return projectName, nil
|
||||
}
|
||||
if s.cfg.ProjectName != "" {
|
||||
return s.cfg.ProjectName, nil
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("无法读取现有容器的 Compose 项目标签:%w", err)
|
||||
}
|
||||
return "", fmt.Errorf("现有 fonu 容器不是由 Compose 管理,无法安全一键升级;请按 Compose 方式重新部署")
|
||||
}
|
||||
|
||||
func (s *Server) discoverHostCompose(ctx context.Context) (string, string, error) {
|
||||
if s.cfg.HostProjectDir != "" {
|
||||
if !filepath.IsAbs(s.cfg.HostProjectDir) {
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestNewServerDefaultsAndValidation(t *testing.T) {
|
||||
|
||||
func TestEnsureComposeFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
server, err := NewServer(Config{ProjectDir: dir, ComposeFile: "docker-compose.yml"}, nil)
|
||||
server, err := NewServer(Config{ProjectDir: dir, ComposeFile: "docker-compose.yml", ProjectName: "fonu"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -69,6 +69,7 @@ func TestResolveComposePlanUsesHostProjectDir(t *testing.T) {
|
||||
ProjectDir: containerDir,
|
||||
ComposeFile: "docker-compose.hub.yml",
|
||||
HostProjectDir: hostDir,
|
||||
ProjectName: "fonu",
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
Reference in New Issue
Block a user