mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-10-03 09:22:56 +00:00
Add a runtime config
This adds support for a runtime configuration file that can do: - `mkdir` to make a directory at runtime, eg in `/var` or `/tmp`, to avoid workarounds - `interface` that can create network interfaces in a container or move them - `bindNS` that can bind mount namespaces of an `onboot` container to a file so a service can be started in that namespace. It merges the `service` and `onboot` tools (in `init`) to avoid duplication. This also saves some size for eg LCOW which did not use the `onboot` code in `runc`. Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
149
pkg/init/cmd/service/system_init.go
Normal file
149
pkg/init/cmd/service/system_init.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func cleanupTask(ctx context.Context, ctr containerd.Container) error {
|
||||
task, err := ctr.Task(ctx, nil)
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
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 && !errdefs.IsNotFound(err) {
|
||||
return errors.Wrapf(err, "killing task with %q", sig)
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-deleteErr:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func systemInitCmd(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", defaultSocket, "Path to containerd socket")
|
||||
path := flags.String("path", defaultPath, "Path to service configs")
|
||||
binary := flags.String("containerd", defaultContainerd, "Path to containerd")
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// remove (unlikely) old containerd socket
|
||||
_ = os.Remove(*sock)
|
||||
|
||||
// start up containerd
|
||||
cmd := exec.Command(*binary)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.WithError(err).Fatal("cannot start containerd")
|
||||
}
|
||||
|
||||
// wait for containerd socket to appear
|
||||
for {
|
||||
_, err := os.Stat(*sock)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
err = cmd.Process.Signal(syscall.Signal(0))
|
||||
if err != nil {
|
||||
// process not there, wait() to find error
|
||||
err = cmd.Wait()
|
||||
log.WithError(err).Fatal("containerd process exited")
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
// connect to containerd
|
||||
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")
|
||||
}
|
||||
|
||||
// Clean up any old 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")
|
||||
}
|
||||
}
|
||||
|
||||
// Start up containers
|
||||
files, err := ioutil.ReadDir(*path)
|
||||
// just skip if there is an error, eg no such path
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, file := range files {
|
||||
if id, pid, msg, err := start(file.Name(), *sock, *path, ""); err != nil {
|
||||
log.WithError(err).Error(msg)
|
||||
} else {
|
||||
log.Debugf("Started %s pid %d", id, pid)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user