linux/shim: reduce memory overhead by using ttrpc

By replacing grpc with ttrpc, we can reduce total memory runtime
requirements and binary size. With minimal code changes, the shim can
now be controlled by the much lightweight protocol, reducing the total
memory required per container.

When reviewing this change, take particular notice of the generated shim
code.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day
2017-11-15 18:06:47 -08:00
parent 8e09b565a7
commit e8f52c35ce
10 changed files with 348 additions and 726 deletions

View File

@@ -4,7 +4,6 @@ package client
import (
"context"
"fmt"
"io"
"net"
"os"
@@ -18,6 +17,7 @@ import (
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/stevvooe/ttrpc"
"github.com/containerd/containerd/events"
"github.com/containerd/containerd/linux/shim"
@@ -26,17 +26,16 @@ import (
"github.com/containerd/containerd/reaper"
"github.com/containerd/containerd/sys"
ptypes "github.com/gogo/protobuf/types"
"google.golang.org/grpc"
)
var empty = &ptypes.Empty{}
// Opt is an option for a shim client configuration
type Opt func(context.Context, shim.Config) (shimapi.ShimClient, io.Closer, error)
type Opt func(context.Context, shim.Config) (shimapi.ShimService, io.Closer, error)
// WithStart executes a new shim process
func WithStart(binary, address, daemonAddress, cgroup string, nonewns, debug bool, exitHandler func()) Opt {
return func(ctx context.Context, config shim.Config) (_ shimapi.ShimClient, _ io.Closer, err error) {
return func(ctx context.Context, config shim.Config) (_ shimapi.ShimService, _ io.Closer, err error) {
socket, err := newSocket(address)
if err != nil {
return nil, nil, err
@@ -139,19 +138,8 @@ func newSocket(address string) (*net.UnixListener, error) {
return l.(*net.UnixListener), nil
}
func connect(address string, d func(string, time.Duration) (net.Conn, error)) (*grpc.ClientConn, error) {
gopts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithInsecure(),
grpc.WithTimeout(100 * time.Second),
grpc.WithDialer(d),
grpc.FailOnNonTempDialError(true),
}
conn, err := grpc.Dial(dialAddress(address), gopts...)
if err != nil {
return nil, errors.Wrapf(err, "failed to dial %q", address)
}
return conn, nil
func connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) {
return d(address, 100*time.Second)
}
func annonDialer(address string, timeout time.Duration) (net.Conn, error) {
@@ -159,24 +147,20 @@ func annonDialer(address string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", "\x00"+address, timeout)
}
func dialAddress(address string) string {
return fmt.Sprintf("unix://%s", address)
}
// WithConnect connects to an existing shim
func WithConnect(address string) Opt {
return func(ctx context.Context, config shim.Config) (shimapi.ShimClient, io.Closer, error) {
return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) {
conn, err := connect(address, annonDialer)
if err != nil {
return nil, nil, err
}
return shimapi.NewShimClient(conn), conn, nil
return shimapi.NewShimClient(ttrpc.NewClient(conn)), conn, nil
}
}
// WithLocal uses an in process shim
func WithLocal(publisher events.Publisher) func(context.Context, shim.Config) (shimapi.ShimClient, io.Closer, error) {
return func(ctx context.Context, config shim.Config) (shimapi.ShimClient, io.Closer, error) {
func WithLocal(publisher events.Publisher) func(context.Context, shim.Config) (shimapi.ShimService, io.Closer, error) {
return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) {
service, err := shim.NewService(config, publisher)
if err != nil {
return nil, nil, err
@@ -192,15 +176,15 @@ func New(ctx context.Context, config shim.Config, opt Opt) (*Client, error) {
return nil, err
}
return &Client{
ShimClient: s,
c: c,
exitCh: make(chan struct{}),
ShimService: s,
c: c,
exitCh: make(chan struct{}),
}, nil
}
// Client is a shim client containing the connection to a shim
type Client struct {
shimapi.ShimClient
shimapi.ShimService
c io.Closer
exitCh chan struct{}
@@ -212,10 +196,9 @@ type Client struct {
func (c *Client) IsAlive(ctx context.Context) (bool, error) {
_, err := c.ShimInfo(ctx, empty)
if err != nil {
if err != grpc.ErrServerStopped {
return false, err
}
return false, nil
// TODO(stevvooe): There are some error conditions that need to be
// handle with unix sockets existence to give the right answer here.
return false, err
}
return true, nil
}