Add config file
This adds a config file for containerd configuration. It is hard to have structure data on cli flags and the config file should be used for the majority of fields when configuring containerd. There are still a few flags on the daemon that override config file values but flags should take a back seat going forward and should be kept at a minimum. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
da8f4bb904
commit
a9950aedcf
16 changed files with 3374 additions and 41 deletions
54
cmd/containerd/config.go
Normal file
54
cmd/containerd/config.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package main
|
||||
|
||||
import "github.com/BurntSushi/toml"
|
||||
|
||||
func defaultConfig() *config {
|
||||
return &config{
|
||||
Root: "/var/lib/containerd",
|
||||
State: "/run/containerd",
|
||||
GRPC: grpcConfig{
|
||||
Socket: "/run/containerd/containerd.sock",
|
||||
},
|
||||
Debug: debug{
|
||||
Level: "info",
|
||||
Socket: "/run/containerd/debug.sock",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// loadConfig loads the config from the provided path
|
||||
func loadConfig(path string) error {
|
||||
_, err := toml.DecodeFile(path, conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// config specifies the containerd configuration file in the TOML format.
|
||||
// It contains fields to configure various subsystems and containerd as a whole.
|
||||
type config struct {
|
||||
// State is the path to a directory where containerd will store runtime state
|
||||
State string `toml:"state"`
|
||||
// Root is the path to a directory where containerd will store persistent data
|
||||
Root string `toml:"root"`
|
||||
// GRPC configuration settings
|
||||
GRPC grpcConfig `toml:"grpc"`
|
||||
// Debug and profiling settings
|
||||
Debug debug `toml:"debug"`
|
||||
// Metrics and monitoring settings
|
||||
Metrics metricsConfig `toml:"metrics"`
|
||||
}
|
||||
|
||||
type grpcConfig struct {
|
||||
Socket string `toml:"socket"`
|
||||
}
|
||||
|
||||
type debug struct {
|
||||
Socket string `toml:"socket"`
|
||||
Level string `toml:"level"`
|
||||
}
|
||||
|
||||
type metricsConfig struct {
|
||||
Address string `toml:"address"`
|
||||
}
|
|
@ -35,7 +35,10 @@ const usage = `
|
|||
high performance container runtime
|
||||
`
|
||||
|
||||
var global = log.WithModule(gocontext.Background(), "containerd")
|
||||
var (
|
||||
conf = defaultConfig()
|
||||
global = log.WithModule(gocontext.Background(), "containerd")
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
|
@ -44,29 +47,25 @@ func main() {
|
|||
app.Usage = usage
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "log-level",
|
||||
Usage: "Set the logging level [debug, info, warn, error, fatal, panic]",
|
||||
Value: "info",
|
||||
Name: "config,c",
|
||||
Usage: "path to the configuration file",
|
||||
Value: "/etc/containerd/config.toml",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "root",
|
||||
Name: "log-level,l",
|
||||
Usage: "set the logging level [debug, info, warn, error, fatal, panic]",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "root,r",
|
||||
Usage: "containerd root directory",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "state",
|
||||
Usage: "containerd state directory",
|
||||
Value: "/run/containerd",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "socket, s",
|
||||
Name: "socket,s",
|
||||
Usage: "socket path for containerd's GRPC server",
|
||||
Value: "/run/containerd/containerd.sock",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "debug-socket, d",
|
||||
Usage: "socket path for containerd's debug server",
|
||||
Value: "/run/containerd/containerd-debug.sock",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "metrics-address, m",
|
||||
Usage: "tcp address to serve metrics on",
|
||||
Value: "127.0.0.1:7897",
|
||||
},
|
||||
}
|
||||
app.Before = before
|
||||
|
@ -78,7 +77,7 @@ func main() {
|
|||
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)
|
||||
|
||||
log.G(global).Info("starting containerd boot...")
|
||||
runtimes, err := loadRuntimes(context)
|
||||
runtimes, err := loadRuntimes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -87,13 +86,13 @@ func main() {
|
|||
return err
|
||||
}
|
||||
// start debug and metrics APIs
|
||||
if err := serveDebugAPI(context); err != nil {
|
||||
if err := serveDebugAPI(); err != nil {
|
||||
return err
|
||||
}
|
||||
serveMetricsAPI(context)
|
||||
serveMetricsAPI()
|
||||
// start the GRPC api with the execution service registered
|
||||
server := newGRPCServer(execution.New(supervisor))
|
||||
if err := serveGRPC(context, server); err != nil {
|
||||
if err := serveGRPC(server); err != nil {
|
||||
return err
|
||||
}
|
||||
log.G(global).Infof("containerd successfully booted in %fs", time.Now().Sub(start).Seconds())
|
||||
|
@ -106,23 +105,60 @@ func main() {
|
|||
}
|
||||
|
||||
func before(context *cli.Context) error {
|
||||
if l := context.GlobalString("log-level"); l != "" {
|
||||
if err := loadConfig(context.GlobalString("config")); err != nil &&
|
||||
!os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
// the order for config vs flag values is that flags will always override
|
||||
// the config values if they are set
|
||||
if err := setLevel(context); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range []struct {
|
||||
name string
|
||||
d *string
|
||||
}{
|
||||
{
|
||||
name: "root",
|
||||
d: &conf.Root,
|
||||
},
|
||||
{
|
||||
name: "state",
|
||||
d: &conf.State,
|
||||
},
|
||||
{
|
||||
name: "socket",
|
||||
d: &conf.GRPC.Socket,
|
||||
},
|
||||
} {
|
||||
if s := context.GlobalString(v.name); s != "" {
|
||||
*v.d = s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setLevel(context *cli.Context) error {
|
||||
l := context.GlobalString("log-level")
|
||||
if l == "" {
|
||||
l = conf.Debug.Level
|
||||
}
|
||||
if l != "" {
|
||||
lvl, err := logrus.ParseLevel(l)
|
||||
if err != nil {
|
||||
lvl = logrus.InfoLevel
|
||||
fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n, and being defaulted to info", l)
|
||||
return err
|
||||
}
|
||||
logrus.SetLevel(lvl)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func serveMetricsAPI(context *cli.Context) {
|
||||
if addr := context.GlobalString("metrics-address"); addr != "" {
|
||||
log.G(global).WithField("metrics", addr).Info("starting metrics API...")
|
||||
func serveMetricsAPI() {
|
||||
if conf.Metrics.Address != "" {
|
||||
log.G(global).WithField("metrics", conf.Metrics.Address).Info("starting metrics API...")
|
||||
h := newMetricsHandler()
|
||||
go func() {
|
||||
if err := http.ListenAndServe(addr, h); err != nil {
|
||||
if err := http.ListenAndServe(conf.Metrics.Address, h); err != nil {
|
||||
log.G(global).WithError(err).Fatal("serve metrics API")
|
||||
}
|
||||
}()
|
||||
|
@ -135,10 +171,10 @@ func newMetricsHandler() http.Handler {
|
|||
return m
|
||||
}
|
||||
|
||||
func serveDebugAPI(context *cli.Context) error {
|
||||
path := context.GlobalString("debug-socket")
|
||||
func serveDebugAPI() error {
|
||||
path := conf.Debug.Socket
|
||||
if path == "" {
|
||||
return errors.New("--debug-socket path cannot be empty")
|
||||
return errors.New("debug socket path cannot be empty")
|
||||
}
|
||||
l, err := utils.CreateUnixSocket(path)
|
||||
if err != nil {
|
||||
|
@ -156,13 +192,10 @@ func serveDebugAPI(context *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func loadRuntimes(context *cli.Context) (map[string]containerd.Runtime, error) {
|
||||
var (
|
||||
root = context.GlobalString("root")
|
||||
o = make(map[string]containerd.Runtime)
|
||||
)
|
||||
func loadRuntimes() (map[string]containerd.Runtime, error) {
|
||||
o := make(map[string]containerd.Runtime)
|
||||
for _, name := range containerd.Runtimes() {
|
||||
r, err := containerd.NewRuntime(name, root)
|
||||
r, err := containerd.NewRuntime(name, conf.State)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -178,8 +211,8 @@ func newGRPCServer(service api.ContainerServiceServer) *grpc.Server {
|
|||
return s
|
||||
}
|
||||
|
||||
func serveGRPC(context *cli.Context, server *grpc.Server) error {
|
||||
path := context.GlobalString("socket")
|
||||
func serveGRPC(server *grpc.Server) error {
|
||||
path := conf.GRPC.Socket
|
||||
if path == "" {
|
||||
return errors.New("--socket path cannot be empty")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ var pprofCommand = cli.Command{
|
|||
cli.StringFlag{
|
||||
Name: "debug-socket, d",
|
||||
Usage: "socket path for containerd's debug server",
|
||||
Value: "/run/containerd/containerd-debug.sock",
|
||||
Value: "/run/containerd/debug.sock",
|
||||
},
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue