
Mounting as MS_SLAVE here breaks use cases which want to use rootPropagation=shared in order to expose mounts to the host (and other containers binding the same subtree), mounting as e.g. MS_SHARED is pointless in this context so just remove. Having done this we also need to arrange to manually clean up the mounts on delete, so do so. Note that runc will also setup root as required by rootPropagation, defaulting to MS_PRIVATE. Fixes #1132. Signed-off-by: Ian Campbell <ian.campbell@docker.com>
158 lines
3.8 KiB
Go
158 lines
3.8 KiB
Go
// +build !windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/containerd/containerd/linux/shim"
|
|
shimapi "github.com/containerd/containerd/linux/shim/v1"
|
|
"github.com/containerd/containerd/reaper"
|
|
"github.com/containerd/containerd/version"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
const usage = `
|
|
__ _ __ __ _
|
|
_________ ____ / /_____ _(_)___ ___ _________/ / _____/ /_ (_)___ ___
|
|
/ ___/ __ \/ __ \/ __/ __ ` + "`" + `/ / __ \/ _ \/ ___/ __ /_____/ ___/ __ \/ / __ ` + "`" + `__ \
|
|
/ /__/ /_/ / / / / /_/ /_/ / / / / / __/ / / /_/ /_____(__ ) / / / / / / / / /
|
|
\___/\____/_/ /_/\__/\__,_/_/_/ /_/\___/_/ \__,_/ /____/_/ /_/_/_/ /_/ /_/
|
|
|
|
shim for container lifecycle and reconnection
|
|
`
|
|
|
|
func main() {
|
|
app := cli.NewApp()
|
|
app.Name = "containerd-shim"
|
|
app.Version = version.Version
|
|
app.Usage = usage
|
|
app.Flags = []cli.Flag{
|
|
cli.BoolFlag{
|
|
Name: "debug",
|
|
Usage: "enable debug output in logs",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "namespace,n",
|
|
Usage: "namespace that owns the task",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "socket,s",
|
|
Usage: "abstract socket path to serve on",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "address,a",
|
|
Usage: "grpc address back to containerd",
|
|
},
|
|
}
|
|
app.Before = func(context *cli.Context) error {
|
|
if context.GlobalBool("debug") {
|
|
logrus.SetLevel(logrus.DebugLevel)
|
|
}
|
|
return nil
|
|
}
|
|
app.Action = func(context *cli.Context) error {
|
|
// start handling signals as soon as possible so that things are properly reaped
|
|
// or if runtime exits before we hit the handler
|
|
signals, err := setupSignals()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
path, err := os.Getwd()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
server := grpc.NewServer()
|
|
sv, err := shim.NewService(
|
|
path,
|
|
context.GlobalString("namespace"),
|
|
context.GlobalString("address"),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logrus.Debug("registering grpc server")
|
|
shimapi.RegisterShimServer(server, sv)
|
|
socket := context.GlobalString("socket")
|
|
if err := serve(server, socket); err != nil {
|
|
return err
|
|
}
|
|
return handleSignals(signals, server)
|
|
}
|
|
if err := app.Run(os.Args); err != nil {
|
|
fmt.Fprintf(os.Stderr, "containerd-shim: %s\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// serve serves the grpc API over a unix socket at the provided path
|
|
// this function does not block
|
|
func serve(server *grpc.Server, path string) error {
|
|
var (
|
|
l net.Listener
|
|
err error
|
|
)
|
|
if path == "" {
|
|
l, err = net.FileListener(os.NewFile(3, "socket"))
|
|
path = "[inherited from parent]"
|
|
} else {
|
|
l, err = net.Listen("unix", "\x00"+path)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logrus.WithField("socket", path).Debug("serving api on unix socket")
|
|
go func() {
|
|
defer l.Close()
|
|
if err := server.Serve(l); err != nil &&
|
|
!strings.Contains(err.Error(), "use of closed network connection") {
|
|
logrus.WithError(err).Fatal("containerd-shim: GRPC server failure")
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func handleSignals(signals chan os.Signal, server *grpc.Server) error {
|
|
for s := range signals {
|
|
logrus.WithField("signal", s).Debug("received signal")
|
|
switch s {
|
|
case unix.SIGCHLD:
|
|
if err := reaper.Reap(); err != nil {
|
|
logrus.WithError(err).Error("reap exit status")
|
|
}
|
|
case unix.SIGTERM, unix.SIGINT:
|
|
// TODO: should we forward signals to the processes if they are still running?
|
|
// i.e. machine reboot
|
|
server.Stop()
|
|
return nil
|
|
case unix.SIGUSR1:
|
|
dumpStacks()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func dumpStacks() {
|
|
var (
|
|
buf []byte
|
|
stackSize int
|
|
)
|
|
bufferLen := 16384
|
|
for stackSize == len(buf) {
|
|
buf = make([]byte, bufferLen)
|
|
stackSize = runtime.Stack(buf, true)
|
|
bufferLen *= 2
|
|
}
|
|
buf = buf[:stackSize]
|
|
logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf)
|
|
}
|