containerd/containerd/main.go

149 lines
3.3 KiB
Go

package main
import (
"fmt"
"net"
"os"
"os/signal"
"sync"
"syscall"
"time"
"google.golang.org/grpc"
"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"github.com/docker/containerd"
"github.com/docker/containerd/api/grpc/server"
"github.com/docker/containerd/api/grpc/types"
"github.com/docker/containerd/osutils"
"github.com/docker/containerd/supervisor"
)
const (
usage = `High performance container daemon`
minRlimit = 1024
)
var daemonFlags = []cli.Flag{
cli.BoolFlag{
Name: "debug",
Usage: "enable debug output in the logs",
},
cli.StringFlag{
Name: "state-dir",
Value: defaultStateDir,
Usage: "runtime state directory",
},
cli.DurationFlag{
Name: "metrics-interval",
Value: 5 * time.Minute,
Usage: "interval for flushing metrics to the store",
},
cli.StringFlag{
Name: "listen,l",
Value: defaultGRPCEndpoint,
Usage: "Address on which GRPC API will listen",
},
cli.StringFlag{
Name: "runtime,r",
Value: "runc",
Usage: "name of the OCI compliant runtime to use when executing containers",
},
}
func main() {
appendPlatformFlags()
app := cli.NewApp()
app.Name = "containerd"
if containerd.GitCommit != "" {
app.Version = fmt.Sprintf("%s commit: %s", containerd.Version, containerd.GitCommit)
} else {
app.Version = containerd.Version
}
app.Usage = usage
app.Flags = daemonFlags
setAppBefore(app)
app.Action = func(context *cli.Context) {
if err := daemon(
context.String("listen"),
context.String("state-dir"),
10,
context.String("runtime"),
); err != nil {
logrus.Fatal(err)
}
}
if err := app.Run(os.Args); err != nil {
logrus.Fatal(err)
}
}
func daemon(address, stateDir string, concurrency int, runtimeName string) error {
// setup a standard reaper so that we don't leave any zombies if we are still alive
// this is just good practice because we are spawning new processes
s := make(chan os.Signal, 2048)
signal.Notify(s, syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT)
if err := osutils.SetSubreaper(1); err != nil {
logrus.WithField("error", err).Error("containerd: set subpreaper")
}
sv, err := supervisor.New(stateDir, runtimeName)
if err != nil {
return err
}
wg := &sync.WaitGroup{}
for i := 0; i < concurrency; i++ {
wg.Add(1)
w := supervisor.NewWorker(sv, wg)
go w.Start()
}
if err := sv.Start(); err != nil {
return err
}
server, err := startServer(address, sv)
if err != nil {
return err
}
for ss := range s {
switch ss {
case syscall.SIGCHLD:
if _, err := osutils.Reap(); err != nil {
logrus.WithField("error", err).Warn("containerd: reap child processes")
}
default:
server.Stop()
os.Exit(0)
}
}
return nil
}
func startServer(address string, sv *supervisor.Supervisor) (*grpc.Server, error) {
if err := os.RemoveAll(address); err != nil {
return nil, err
}
l, err := net.Listen(defaultListenType, address)
if err != nil {
return nil, err
}
s := grpc.NewServer()
types.RegisterAPIServer(s, server.NewServer(sv))
go func() {
logrus.Debugf("containerd: grpc api on %s", address)
if err := s.Serve(l); err != nil {
logrus.WithField("error", err).Fatal("containerd: serve grpc")
}
}()
return s, nil
}
// getDefaultID returns the hostname for the instance host
func getDefaultID() string {
hostname, err := os.Hostname()
if err != nil {
panic(err)
}
return hostname
}