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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user