Load runtimes dynamically via go1.8 plugins
Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Add registration for more subsystems via plugins Signed-off-by: Michael Crosby <crosbymichael@gmail.com> Move content service to separate package Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
b7805198b1
commit
3101be93bc
25 changed files with 435 additions and 264 deletions
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/containerd"
|
||||
shimapi "github.com/docker/containerd/api/services/shim"
|
||||
"github.com/docker/containerd/shim"
|
||||
"github.com/docker/containerd/linux/shim"
|
||||
"github.com/docker/containerd/sys"
|
||||
"github.com/docker/containerd/utils"
|
||||
"github.com/urfave/cli"
|
||||
|
|
7
cmd/containerd/builtins.go
Normal file
7
cmd/containerd/builtins.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
// register containerd builtins here
|
||||
import (
|
||||
_ "github.com/docker/containerd/services/content"
|
||||
_ "github.com/docker/containerd/services/execution"
|
||||
)
|
|
@ -18,10 +18,11 @@ func defaultConfig() *config {
|
|||
|
||||
// loadConfig loads the config from the provided path
|
||||
func loadConfig(path string) error {
|
||||
_, err := toml.DecodeFile(path, conf)
|
||||
md, err := toml.DecodeFile(path, conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.md = md
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,18 @@ type config struct {
|
|||
Debug debug `toml:"debug"`
|
||||
// Metrics and monitoring settings
|
||||
Metrics metricsConfig `toml:"metrics"`
|
||||
// Plugins provides plugin specific configuration for the initialization of a plugin
|
||||
Plugins map[string]toml.Primitive `toml:"plugins"`
|
||||
|
||||
md toml.MetaData
|
||||
}
|
||||
|
||||
func (c *config) decodePlugin(name string, v interface{}) error {
|
||||
p, ok := c.Plugins[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return c.md.PrimitiveDecode(p, v)
|
||||
}
|
||||
|
||||
type grpcConfig struct {
|
||||
|
|
|
@ -16,12 +16,9 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/containerd"
|
||||
contentapi "github.com/docker/containerd/api/services/content"
|
||||
api "github.com/docker/containerd/api/services/execution"
|
||||
"github.com/docker/containerd/content"
|
||||
_ "github.com/docker/containerd/linux"
|
||||
"github.com/docker/containerd/log"
|
||||
"github.com/docker/containerd/services/execution"
|
||||
"github.com/docker/containerd/utils"
|
||||
metrics "github.com/docker/go-metrics"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -66,6 +63,10 @@ func main() {
|
|||
Name: "socket,s",
|
||||
Usage: "socket path for containerd's GRPC server",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "root",
|
||||
Usage: "containerd root directory",
|
||||
},
|
||||
}
|
||||
app.Before = before
|
||||
app.Action = func(context *cli.Context) error {
|
||||
|
@ -74,37 +75,41 @@ func main() {
|
|||
// we don't miss any signals during boot
|
||||
signals := make(chan os.Signal, 2048)
|
||||
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)
|
||||
|
||||
log.G(global).Info("starting containerd boot...")
|
||||
runtimes, err := loadRuntimes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
supervisor, err := containerd.NewSupervisor(log.WithModule(global, "execution"), runtimes)
|
||||
if err != nil {
|
||||
|
||||
// load all plugins into containerd
|
||||
if err := containerd.Load(filepath.Join(conf.Root, "plugins")); err != nil {
|
||||
return err
|
||||
}
|
||||
// start debug and metrics APIs
|
||||
if err := serveDebugAPI(); err != nil {
|
||||
return err
|
||||
}
|
||||
serveMetricsAPI()
|
||||
|
||||
contentStore, err := resolveContentStore()
|
||||
runtimes, err := loadRuntimes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
store, err := resolveContentStore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services, err := loadServices(runtimes, store)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// start the GRPC api with the execution service registered
|
||||
server := newGRPCServer()
|
||||
|
||||
api.RegisterContainerServiceServer(server, execution.New(supervisor))
|
||||
contentapi.RegisterContentServer(server, content.NewService(contentStore))
|
||||
|
||||
// start the GRPC api with registered services
|
||||
for _, service := range services {
|
||||
if err := service.Register(server); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := serveGRPC(server); err != nil {
|
||||
return err
|
||||
}
|
||||
// start the prometheus metrics API for containerd
|
||||
serveMetricsAPI()
|
||||
|
||||
log.G(global).Infof("containerd successfully booted in %fs", time.Now().Sub(start).Seconds())
|
||||
return handleSignals(signals, server)
|
||||
}
|
||||
|
@ -209,14 +214,28 @@ func resolveContentStore() (*content.Store, error) {
|
|||
}
|
||||
|
||||
func loadRuntimes() (map[string]containerd.Runtime, error) {
|
||||
o := map[string]containerd.Runtime{}
|
||||
for _, name := range containerd.Runtimes() {
|
||||
r, err := containerd.NewRuntime(name, conf.State)
|
||||
o := make(map[string]containerd.Runtime)
|
||||
for name, rr := range containerd.Registrations() {
|
||||
if rr.Type != containerd.RuntimePlugin {
|
||||
continue
|
||||
}
|
||||
log.G(global).Infof("loading runtime plugin %q...", name)
|
||||
ic := &containerd.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Context: log.WithModule(global, fmt.Sprintf("runtime-%s", name)),
|
||||
}
|
||||
if rr.Config != nil {
|
||||
if err := conf.decodePlugin(name, rr.Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ic.Config = rr.Config
|
||||
}
|
||||
vr, err := rr.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o[name] = r
|
||||
log.G(global).WithField("runtime", name).Info("load runtime")
|
||||
o[name] = vr.(containerd.Runtime)
|
||||
}
|
||||
return o, nil
|
||||
}
|
||||
|
@ -226,6 +245,35 @@ func newGRPCServer() *grpc.Server {
|
|||
return s
|
||||
}
|
||||
|
||||
func loadServices(runtimes map[string]containerd.Runtime, store *content.Store) ([]containerd.Service, error) {
|
||||
var o []containerd.Service
|
||||
for name, sr := range containerd.Registrations() {
|
||||
if sr.Type != containerd.GRPCPlugin {
|
||||
continue
|
||||
}
|
||||
log.G(global).Infof("loading grpc service plugin %q...", name)
|
||||
ic := &containerd.InitContext{
|
||||
Root: conf.Root,
|
||||
State: conf.State,
|
||||
Context: log.WithModule(global, fmt.Sprintf("service-%s", name)),
|
||||
Runtimes: runtimes,
|
||||
Store: store,
|
||||
}
|
||||
if sr.Config != nil {
|
||||
if err := conf.decodePlugin(name, sr.Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ic.Config = sr.Config
|
||||
}
|
||||
vs, err := sr.Init(ic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o = append(o, vs.(containerd.Service))
|
||||
}
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func serveGRPC(server *grpc.Server) error {
|
||||
path := conf.GRPC.Socket
|
||||
if path == "" {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue