Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gracefully stop blueprint containers before committing them #363

Merged
merged 3 commits into from
Apr 27, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions internal/docker/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,18 @@ func (d *Builder) construct(bprint b.Blueprint) (errs []error) {
}
// kill the container
defer func(r result) {
containerInfo, err := d.Docker.ContainerInspect(context.Background(), r.containerID)

if err != nil {
d.log("%s : Can't get status of %s", r.contextStr, r.containerID)
return
}

if !containerInfo.State.Running {
// The container isn't running anyway, so no need to kill it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are now stopping the containers so I don't see how containerInfo.State.Running can ever be true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a great deal of Go experience, but I view this defer as a last-resort clean-up mechanism, like a finally block in Java/etc. Anecdotally, I've had docker stop leave a container running before, but frankly this may well have been a bug (I'm not sure). I'm happy to remove it if you think that's best, but it really was just intended as a last resort 'stopping gracefully is nice, but littering the host with containers is to be avoided if at all possible'.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you've seen this in the wild then let's leave it in. Docker is async command wise (you'll note several places we repeat the same instruction until timeout/success) so I can believe it not stopping the container when you ask for it to stop.

return
}

killErr := d.Docker.ContainerKill(context.Background(), r.containerID, "KILL")
if killErr != nil {
d.log("%s : Failed to kill container %s: %s\n", r.contextStr, r.containerID, killErr)
Expand Down Expand Up @@ -298,6 +310,17 @@ func (d *Builder) construct(bprint b.Blueprint) (errs []error) {
labels[k] = v
}

// Stop the container before we commit it.
// This gives it chance to shut down gracefully.
// If we don't do this, then e.g. Postgres databases can become corrupt, which
// then incurs a slow recovery process when we use the blueprint later.
d.log("%s: Stopping container: %s", res.contextStr, res.containerID)
timeout := 10 * time.Second
d.Docker.ContainerStop(context.Background(), res.containerID, &timeout)

// Log again so we can see the timings.
d.log("%s: Stopped container: %s", res.contextStr, res.containerID)

// commit the container
commit, err := d.Docker.ContainerCommit(context.Background(), res.containerID, types.ContainerCommitOptions{
Author: "Complement",
Expand Down