containerd: Add a service command to cleanup stale containers on boot

This may occur if /var/lib/container happens to be on persistent storage.

Signed-off-by: Ian Campbell <ijc@docker.com>
This commit is contained in:
Ian Campbell 2017-07-13 17:15:20 +01:00
parent 4eb0f00db6
commit 538c8b5a7b
4 changed files with 107 additions and 1 deletions

View File

@ -1,5 +1,5 @@
IMAGE=containerd
NETWORK=1
DEPS=$(wildcard etc/init.d/*) etc/containerd/config.toml
DEPS=$(wildcard etc/init.d/*) $(wildcard cmd/service/*.go) etc/containerd/config.toml
include ../package.mk

View File

@ -29,6 +29,7 @@ func main() {
flag.Usage = func() {
fmt.Printf("USAGE: %s [options] COMMAND\n\n", filepath.Base(os.Args[0]))
fmt.Printf("Commands:\n")
fmt.Printf(" system-init Prepare the system at start of day\n")
fmt.Printf(" start Start a service\n")
fmt.Printf(" help Print this message\n")
fmt.Printf("\n")
@ -67,6 +68,8 @@ func main() {
switch args[0] {
case "start":
start(args[1:])
case "system-init":
systemInit(args[1:])
default:
fmt.Printf("%q is not valid command.\n\n", args[0])
flag.Usage()

View File

@ -0,0 +1,101 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"syscall"
log "github.com/Sirupsen/logrus"
"github.com/containerd/containerd"
"github.com/containerd/containerd/namespaces"
"github.com/pkg/errors"
)
func cleanupTask(ctx context.Context, ctr containerd.Container) error {
task, err := ctr.Task(ctx, nil)
if err != nil {
if err == containerd.ErrNoRunningTask {
return nil
}
return errors.Wrap(err, "getting task")
}
deleteErr := make(chan error, 1)
deleteCtx, deleteCancel := context.WithCancel(ctx)
defer deleteCancel()
go func(ctx context.Context, ch chan error) {
_, err := task.Delete(ctx)
if err != nil {
ch <- errors.Wrap(err, "killing task")
}
ch <- nil
}(deleteCtx, deleteErr)
sig := syscall.SIGKILL
if err := task.Kill(ctx, sig); err != nil && err != containerd.ErrProcessExited {
return errors.Wrapf(err, "killing task with %q", sig)
}
select {
case err := <-deleteErr:
return err
case <-ctx.Done():
return ctx.Err()
}
}
func systemInit(args []string) {
invoked := filepath.Base(os.Args[0])
flags := flag.NewFlagSet("system-init", flag.ExitOnError)
flags.Usage = func() {
fmt.Printf("USAGE: %s system-init\n\n", invoked)
fmt.Printf("Options:\n")
flags.PrintDefaults()
}
sock := flags.String("sock", "/run/containerd/containerd.sock", "Path to containerd socket")
if err := flags.Parse(args); err != nil {
log.Fatal("Unable to parse args")
}
args = flags.Args()
if len(args) != 0 {
fmt.Println("Unexpected argument")
flags.Usage()
os.Exit(1)
}
client, err := containerd.New(*sock)
if err != nil {
log.WithError(err).Fatal("creating containerd client")
}
ctx := namespaces.WithNamespace(context.Background(), "default")
ctrs, err := client.Containers(ctx)
if err != nil {
log.WithError(err).Fatal("listing containers")
}
// None of the errors in this loop are fatal since we want to
// keep trying.
for _, ctr := range ctrs {
log.Infof("Cleaning up stale service: %q", ctr.ID())
log := log.WithFields(log.Fields{
"service": ctr.ID(),
})
if err := cleanupTask(ctx, ctr); err != nil {
log.WithError(err).Error("cleaning up task")
}
if err := ctr.Delete(ctx); err != nil {
log.WithError(err).Error("deleting container")
}
}
}

View File

@ -12,6 +12,8 @@ done
# start service containers
service system-init
if [ -d /containers/services ]
then
for f in $(find /containers/services -mindepth 1 -maxdepth 1 | sort)