Skip to content

Commit fb7807a

Browse files
committed
Jailer leaves containers behind
The jailer will leave containers behind if the jailing process was killed with SIGKILL. Signed-off-by: xibz <[email protected]>
1 parent 4a29fac commit fb7807a

File tree

6 files changed

+60
-7
lines changed

6 files changed

+60
-7
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/containerd/containerd v1.3.3
99
github.com/containerd/continuity v0.0.0-20181027224239-bea7585dbfac // indirect
1010
github.com/containerd/fifo v0.0.0-20190816180239-bda0ff6ed73c
11-
github.com/containerd/go-runc v0.0.0-20190226155025-7d11b49dc076 // indirect
11+
github.com/containerd/go-runc v0.0.0-20190226155025-7d11b49dc076
1212
github.com/containerd/ttrpc v0.0.0-20190613183316-1fb3814edf44
1313
github.com/containerd/typeurl v0.0.0-20181015155603-461401dc8f19
1414
github.com/containernetworking/cni v0.7.2-0.20190807151350-8c6c47d1c7fc

runtime/jailer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type jailer interface {
5555
// StubDrivesOptions will return a set of options used to create a new stub
5656
// drive file
5757
StubDrivesOptions() []FileOpt
58+
// Close will do any necessary cleanup that the jailer has accrued.
59+
Close() error
5860
}
5961

6062
type cgroupPather interface {

runtime/noop_jailer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ func (j noopJailer) StubDrivesOptions() []FileOpt {
7979
j.logger.Debug("noop operation for StubDrivesOptions")
8080
return []FileOpt{}
8181
}
82+
83+
func (j noopJailer) Close() error { return nil }

runtime/runc_jailer.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"strings"
2525
"syscall"
2626

27+
"github.com/containerd/go-runc"
2728
"github.com/firecracker-microvm/firecracker-go-sdk"
2829
"github.com/opencontainers/runtime-spec/specs-go"
2930
"github.com/pkg/errors"
@@ -46,6 +47,7 @@ type runcJailer struct {
4647
Config runcJailerConfig
4748
vmID string
4849
configSpec specs.Spec
50+
runcClient runc.Runc
4951
}
5052

5153
const firecrackerFileName = "firecracker"
@@ -64,10 +66,11 @@ func newRuncJailer(ctx context.Context, logger *logrus.Entry, vmID string, cfg r
6466
WithField("runcBinaryPath", cfg.RuncBinPath)
6567

6668
j := &runcJailer{
67-
ctx: ctx,
68-
logger: l,
69-
Config: cfg,
70-
vmID: vmID,
69+
ctx: ctx,
70+
logger: l,
71+
Config: cfg,
72+
vmID: vmID,
73+
runcClient: runc.Runc{},
7174
}
7275

7376
spec := specs.Spec{}
@@ -447,6 +450,14 @@ func (j *runcJailer) setDefaultConfigValues(cfg *config.Config, socketPath strin
447450
return spec
448451
}
449452

453+
// Close will cleanup the container that may be left behind if the jailing
454+
// process was killed via SIGKILL.
455+
func (j *runcJailer) Close() error {
456+
return j.runcClient.Delete(j.ctx, j.vmID, &runc.DeleteOpts{
457+
Force: true,
458+
})
459+
}
460+
450461
func mkdirAndChown(path string, mode os.FileMode, uid, gid uint32) error {
451462
if err := os.Mkdir(path, mode); err != nil {
452463
return err

runtime/service.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,8 +1278,16 @@ func (s *service) Cleanup(requestCtx context.Context) (*taskAPI.DeleteResponse,
12781278
}
12791279

12801280
func (s *service) monitorVMExit() {
1281-
// once the VM shuts down, the shim should too
1282-
defer s.shimCancel()
1281+
defer func() {
1282+
// we ignore the error here due to cleanup will only succeed if the jailing
1283+
// process was killed via SIGKILL
1284+
if err := s.jailer.Close(); err != nil {
1285+
s.logger.WithError(err).Error("failed to close jailer")
1286+
}
1287+
1288+
// once the VM shuts down, the shim should too
1289+
s.shimCancel()
1290+
}()
12831291

12841292
// Block until the VM exits
12851293
s.vmExitErr = s.machine.Wait(s.shimCtx)

runtime/service_integ_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/containerd/containerd/oci"
3636
"github.com/containerd/containerd/pkg/ttrpcutil"
3737
"github.com/containerd/containerd/runtime"
38+
"github.com/containerd/go-runc"
3839
"github.com/containerd/typeurl"
3940
"github.com/containernetworking/plugins/pkg/ns"
4041
"github.com/opencontainers/runtime-spec/specs-go"
@@ -64,6 +65,7 @@ const (
6465
firecrackerRuntime = "aws.firecracker"
6566
shimProcessName = "containerd-shim-aws-firecracker"
6667
firecrackerProcessName = "firecracker"
68+
jailerProcessName = "runc"
6769

6870
defaultVMRootfsPath = "/var/lib/firecracker-containerd/runtime/default-rootfs.img"
6971
defaultVMNetDevName = "eth0"
@@ -74,6 +76,7 @@ const (
7476
var (
7577
findShim = findProcWithName(shimProcessName)
7678
findFirecracker = findProcWithName(firecrackerProcessName)
79+
findJailer = findProcWithName(jailerProcessName)
7780
)
7881

7982
// Images are presumed by the isolated tests to have already been pulled
@@ -1364,6 +1367,33 @@ func TestStopVM_Isolated(t *testing.T) {
13641367
require.Equal(status.Code(err), codes.OK)
13651368
},
13661369
},
1370+
{
1371+
name: "Jailer SIGKILL",
1372+
createVMRequest: proto.CreateVMRequest{
1373+
JailerConfig: &proto.JailerConfig{
1374+
UID: 300000,
1375+
GID: 300000,
1376+
},
1377+
},
1378+
stopFunc: func(ctx context.Context, fcClient fccontrol.FirecrackerService, vmID string) {
1379+
firecrackerProcesses, err := internal.WaitForProcessToExist(ctx, time.Second, findJailer)
1380+
require.NoError(err, "failed waiting for expected firecracker process %q to come up", firecrackerProcessName)
1381+
require.Len(firecrackerProcesses, 1, "expected only one firecracker process to exist")
1382+
firecrackerProcess := firecrackerProcesses[0]
1383+
1384+
err = firecrackerProcess.KillWithContext(ctx)
1385+
require.NoError(err, "failed to kill firecracker process")
1386+
1387+
// Sleep here to ensure runc finishes execution
1388+
time.Sleep(500 * time.Millisecond)
1389+
1390+
// ensure that the jailer has cleaned up all of the containers
1391+
runcClient := &runc.Runc{}
1392+
containers, err := runcClient.List(ctx)
1393+
require.NoError(err, "failed to run 'runc list'")
1394+
assert.Equal(0, len(containers))
1395+
},
1396+
},
13671397

13681398
// Firecracker is too fast to test a case where we hit the timeout on a StopVMRequest.
13691399
// The rootfs below explicitly sleeps 60 seconds after shutting down the agent to simulate the case.

0 commit comments

Comments
 (0)