client, ctr: allow specifying unmanaged rootfs dir

e.g. ctr run -t --rm --rootfs /tmp/busybox-rootfs foo /bin/sh
(--rm removes the container but does not remove rootfs dir, of course)

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2017-07-13 09:53:32 +00:00
parent 1a054c67b1
commit 752d253f40
3 changed files with 74 additions and 56 deletions

View File

@ -47,7 +47,7 @@ func withMounts(context *cli.Context) containerd.SpecOpts {
var runCommand = cli.Command{
Name: "run",
Usage: "run a container",
ArgsUsage: "IMAGE CONTAINER [COMMAND] [ARG...]",
ArgsUsage: "Image|RootFS ID [COMMAND] [ARG...]",
Flags: append([]cli.Flag{
cli.BoolFlag{
Name: "tty,t",

View File

@ -18,6 +18,13 @@ import (
"github.com/urfave/cli"
)
func init() {
runCommand.Flags = append(runCommand.Flags, cli.BoolFlag{
Name: "rootfs",
Usage: "Use custom rootfs that is not managed by containerd snapshotter.",
})
}
func handleConsoleResize(ctx gocontext.Context, task resizer, con console.Console) error {
// do an initial resize of the console
size, err := con.Size()
@ -54,38 +61,50 @@ func setHostNetworking() containerd.SpecOpts {
func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
var (
err error
checkpointIndex digest.Digest
ref = context.Args().First()
id = context.Args().Get(1)
args = context.Args()[2:]
tty = context.Bool("tty")
labelStrings = context.StringSlice("label")
)
labels := labelArgs(labelStrings)
if raw := context.String("checkpoint"); raw != "" {
if checkpointIndex, err = digest.Parse(raw); err != nil {
checkpointIndex, err := digest.Parse(raw)
if err != nil {
return nil, err
}
if checkpointIndex != "" {
return client.NewContainer(ctx, id, containerd.WithCheckpoint(v1.Descriptor{
Digest: checkpointIndex,
}, id))
}
}
var (
opts []containerd.SpecOpts
cOpts []containerd.NewContainerOpts
)
cOpts = append(cOpts, containerd.WithContainerLabels(labelArgs(context.StringSlice("label"))))
if context.Bool("rootfs") {
opts = append(opts, containerd.WithRootFSPath(ref, context.Bool("readonly")))
} else {
image, err := client.GetImage(ctx, ref)
if err != nil {
return nil, err
}
if checkpointIndex == "" {
opts := []containerd.SpecOpts{
containerd.WithImageConfig(ctx, image),
withEnv(context),
withMounts(context),
opts = append(opts, containerd.WithImageConfig(ctx, image))
cOpts = append(cOpts, containerd.WithImage(image))
if context.Bool("readonly") {
cOpts = append(cOpts, containerd.WithNewSnapshotView(id, image))
} else {
cOpts = append(cOpts, containerd.WithNewSnapshot(id, image))
}
cOpts = append(cOpts, containerd.WithSnapshotter(context.String("snapshotter")))
}
opts = append(opts, withEnv(context), withMounts(context))
if len(args) > 0 {
opts = append(opts, containerd.WithProcessArgs(args...))
}
if tty {
if context.Bool("tty") {
opts = append(opts, withTTY())
}
if context.Bool("net-host") {
@ -95,25 +114,8 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
if err != nil {
return nil, err
}
var rootfs containerd.NewContainerOpts
if context.Bool("readonly") {
rootfs = containerd.WithNewSnapshotView(id, image)
} else {
rootfs = containerd.WithNewSnapshot(id, image)
}
return client.NewContainer(ctx, id,
containerd.WithSpec(spec),
containerd.WithImage(image),
containerd.WithContainerLabels(labels),
containerd.WithSnapshotter(context.String("snapshotter")),
rootfs,
)
}
return client.NewContainer(ctx, id, containerd.WithCheckpoint(v1.Descriptor{
Digest: checkpointIndex,
}, id))
cOpts = append([]containerd.NewContainerOpts{containerd.WithSpec(spec)}, cOpts...)
return client.NewContainer(ctx, id, cOpts...)
}
func newTask(ctx gocontext.Context, container containerd.Container, checkpoint digest.Digest, tty bool) (containerd.Task, error) {

View File

@ -30,6 +30,12 @@ const (
defaultRootfsPath = "rootfs"
)
var (
defaultEnv = []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
)
func defaltCaps() []string {
return []string{
"CAP_CHOWN",
@ -76,6 +82,7 @@ func createDefaultSpec() (*specs.Spec, error) {
Path: defaultRootfsPath,
},
Process: &specs.Process{
Env: defaultEnv,
Cwd: "/",
NoNewPrivileges: true,
User: specs.User{
@ -220,10 +227,7 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
default:
return fmt.Errorf("unknown image config media type %s", ic.MediaType)
}
env := []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
s.Process.Env = append(env, config.Env...)
s.Process.Env = append(s.Process.Env, config.Env...)
var (
uid, gid uint32
)
@ -262,6 +266,18 @@ func WithImageConfig(ctx context.Context, i Image) SpecOpts {
}
}
// WithRootFSPath specifies unmanaged rootfs path.
func WithRootFSPath(path string, readonly bool) SpecOpts {
return func(s *specs.Spec) error {
s.Root = &specs.Root{
Path: path,
Readonly: readonly,
}
// Entrypoint is not set here (it's up to caller)
return nil
}
}
// WithSpec sets the provided spec for a new container
func WithSpec(spec *specs.Spec) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {