feat: auto-update app-dono-cliente when a new image is pushed to :latest

Adds a StepRunUpdater step that starts app-dono-updater after the app
container comes up: a poll loop (docker pull, compare image IDs,
recreate on change) baked into the official docker:cli image via
`sh -c`, reusing the same docker run argv as the initial container
start so the two can't drift.

Not built on Watchtower: containrrr/watchtower was archived upstream
in Dec 2025 with no maintained successor recommended for production
use, so this avoids taking on that dependency.
This commit is contained in:
2026-08-26 12:30:44 -03:00
parent ef126eaf61
commit a05b98fdf5
8 changed files with 244 additions and 18 deletions
+46
View File
@@ -11,6 +11,7 @@ import (
const (
imageName = "hub.davinti.com.br:443/app-dono/app-cliente:latest"
wireguardImageName = "hub.davinti.com.br:443/davinti-vproxy:latest"
updaterImageName = "docker:cli"
configPath = "config.toml"
wireguardConfigPath = "envs"
)
@@ -138,6 +139,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m.updateGenerateFile(msg)
case StepRunDocker:
return m.updateRunDocker(msg)
case StepRunUpdater:
return m.updateRunUpdater(msg)
case StepDone:
return m, tea.Quit
}
@@ -396,6 +399,49 @@ func (m Model) updateRunDocker(msg tea.Msg) (tea.Model, tea.Cmd) {
default:
return m, tea.Quit
}
} else if m.finishedDockerRun && m.dockerRunError == nil {
m.currentStep = StepRunUpdater
m.finishedDockerRun = false
m.dockerRunError = nil
return m, RunUpdaterContainer(
imageName,
"app-dono-cliente",
configPath,
fmt.Sprintf("/app/%s", configPath),
m.configValues,
)
}
}
return m, nil
}
// updateRunUpdater starts the auto-update agent that watches the app-dono-cliente
// container and pulls/recreates it whenever a new image is pushed to :latest.
func (m Model) updateRunUpdater(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case DockerRunMsg:
m.finishedDockerRun = true
m.dockerRunError = msg.Err
case tea.KeyPressMsg:
if m.finishedDockerRun && m.dockerRunError != nil {
switch msg.String() {
case "r":
m.finishedDockerRun = false
m.dockerRunError = nil
return m, RunUpdaterContainer(
imageName,
"app-dono-cliente",
configPath,
fmt.Sprintf("/app/%s", configPath),
m.configValues,
)
default:
return m, tea.Quit
}
} else if m.finishedDockerRun && m.dockerRunError == nil {
m.currentStep = StepDone
}