命令:
shim for container lifecycle and reconnection
USAGE:
containerd-shim [global options] command [command options] [arguments...]
VERSION:
v1.0.0-alpha3.m
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--debug enable debug output in logs
--namespace value, -n value namespace that owns the task
--socket value, -s value abstract socket path to serve on
--address value, -a value grpc address back to containerd
--help, -h show help
--version, -v print the version
一. containerd-shim main 函数
1.1 入口目录为 cmd/containerd/main.go 中 main 函数,NewApp 使用了第三方一个命令行设置,设置名字,以及命令行启动参数,子命令等
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
}
1.2 app.Action 主要是建立 GRPC 服务,以及创建 shim 服务
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()
e, err := connectEvents(context.GlobalString("address"))
if err != nil {
return err
}
sv, err := shim.NewService(
path,
context.GlobalString("namespace"),
&remoteEventsPublisher{client: e},
)
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)
}
1.3 NewService 如下
// NewService returns a new shim service that can be used via GRPC
func NewService(path, namespace string, publisher events.Publisher) (*Service, error) {
if namespace == "" {
return nil, fmt.Errorf("shim namespace cannot be empty")
}
context := namespaces.WithNamespace(context.Background(), namespace)
s := &Service{
path: path,
processes: make(map[string]process),
events: make(chan interface{}, 4096),
namespace: namespace,
context: context,
}
if err := s.initPlatform(); err != nil {
return nil, errors.Wrap(err, "failed to initialized platform behavior")
}
go s.forward(publisher)
return s, nil
}
1.4 serve 如果没有指定 --socket 则从父继承过来
// 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
}