Fix container name conflict on redeployment
Remove old container before creating new one instead of trying to keep it for rollback. Rollback isn't safe anyway because database migrations may have been applied by the new container. The old stop-then-rollback approach failed because Docker doesn't allow two containers with the same name, even if one is stopped.
This commit is contained in:
parent
d2f2747ae6
commit
83986626a4
@ -307,7 +307,7 @@ func (svc *Service) buildImageWithTimeout(
|
||||
}
|
||||
|
||||
// deployContainerWithTimeout runs the deploy phase with a timeout.
|
||||
// It stops the old container, starts the new one, and handles rollback on failure.
|
||||
// It removes the old container and starts the new one.
|
||||
func (svc *Service) deployContainerWithTimeout(
|
||||
ctx context.Context,
|
||||
app *models.App,
|
||||
@ -322,17 +322,12 @@ func (svc *Service) deployContainerWithTimeout(
|
||||
return err
|
||||
}
|
||||
|
||||
// Stop old container (but don't remove yet - keep for potential rollback)
|
||||
oldContainerID := svc.stopOldContainer(deployCtx, app, deployment)
|
||||
// Remove old container first to free up the name
|
||||
svc.removeOldContainer(deployCtx, app, deployment)
|
||||
|
||||
// Try to create and start the new container
|
||||
// Create and start the new container
|
||||
_, err = svc.createAndStartContainer(deployCtx, app, deployment, imageID)
|
||||
if err != nil {
|
||||
// Rollback: restart the old container if we have one
|
||||
if oldContainerID != "" {
|
||||
svc.rollbackContainer(ctx, oldContainerID, deployment)
|
||||
}
|
||||
|
||||
if errors.Is(deployCtx.Err(), context.DeadlineExceeded) {
|
||||
timeoutErr := fmt.Errorf("%w after %v", ErrDeployTimeout, deployTimeout)
|
||||
svc.failDeployment(ctx, app, deployment, timeoutErr)
|
||||
@ -343,11 +338,6 @@ func (svc *Service) deployContainerWithTimeout(
|
||||
return err
|
||||
}
|
||||
|
||||
// Success: remove the old container
|
||||
if oldContainerID != "" {
|
||||
svc.removeContainer(ctx, oldContainerID, deployment)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -627,19 +617,18 @@ func (svc *Service) updateDeploymentDeploying(
|
||||
return nil
|
||||
}
|
||||
|
||||
// stopOldContainer stops the old container but keeps it for potential rollback.
|
||||
// Returns the container ID if found, empty string otherwise.
|
||||
func (svc *Service) stopOldContainer(
|
||||
// removeOldContainer stops and removes the old container before deploying a new one.
|
||||
func (svc *Service) removeOldContainer(
|
||||
ctx context.Context,
|
||||
app *models.App,
|
||||
deployment *models.Deployment,
|
||||
) string {
|
||||
) {
|
||||
containerInfo, err := svc.docker.FindContainerByAppID(ctx, app.ID)
|
||||
if err != nil || containerInfo == nil {
|
||||
return ""
|
||||
return
|
||||
}
|
||||
|
||||
svc.log.Info("stopping old container", "id", containerInfo.ID)
|
||||
svc.log.Info("removing old container", "id", containerInfo.ID)
|
||||
|
||||
if containerInfo.Running {
|
||||
stopErr := svc.docker.StopContainer(ctx, containerInfo.ID)
|
||||
@ -648,47 +637,12 @@ func (svc *Service) stopOldContainer(
|
||||
}
|
||||
}
|
||||
|
||||
_ = deployment.AppendLog(ctx, "Old container stopped: "+containerInfo.ID[:12])
|
||||
|
||||
return containerInfo.ID
|
||||
}
|
||||
|
||||
// rollbackContainer restarts the old container after a failed deployment.
|
||||
func (svc *Service) rollbackContainer(
|
||||
ctx context.Context,
|
||||
containerID string,
|
||||
deployment *models.Deployment,
|
||||
) {
|
||||
svc.log.Info("rolling back to old container", "id", containerID)
|
||||
_ = deployment.AppendLog(ctx, "Rolling back to previous container: "+containerID[:12])
|
||||
|
||||
startErr := svc.docker.StartContainer(ctx, containerID)
|
||||
if startErr != nil {
|
||||
svc.log.Error("failed to restart old container during rollback", "error", startErr)
|
||||
_ = deployment.AppendLog(ctx, "ERROR: Failed to rollback: "+startErr.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_ = deployment.AppendLog(ctx, "Rollback successful - previous container restarted")
|
||||
}
|
||||
|
||||
// removeContainer removes a container after successful deployment.
|
||||
func (svc *Service) removeContainer(
|
||||
ctx context.Context,
|
||||
containerID string,
|
||||
deployment *models.Deployment,
|
||||
) {
|
||||
svc.log.Info("removing old container", "id", containerID)
|
||||
|
||||
removeErr := svc.docker.RemoveContainer(ctx, containerID, true)
|
||||
removeErr := svc.docker.RemoveContainer(ctx, containerInfo.ID, true)
|
||||
if removeErr != nil {
|
||||
svc.log.Warn("failed to remove old container", "error", removeErr)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_ = deployment.AppendLog(ctx, "Old container removed: "+containerID[:12])
|
||||
_ = deployment.AppendLog(ctx, "Old container removed: "+containerInfo.ID[:12])
|
||||
}
|
||||
|
||||
func (svc *Service) createAndStartContainer(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user