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:
Michael Crosby 2017-02-16 14:45:13 -08:00
parent b7805198b1
commit 3101be93bc
25 changed files with 435 additions and 264 deletions

View file

@ -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"

View file

@ -0,0 +1,7 @@
package main
// register containerd builtins here
import (
_ "github.com/docker/containerd/services/content"
_ "github.com/docker/containerd/services/execution"
)

View file

@ -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 {

View file

@ -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 == "" {