Skip to content

Commit fe5f3d5

Browse files
committed
Add proper handling for SIGKILL'ed shim
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
1 parent dd71165 commit fe5f3d5

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

containerd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/docker/containerd/api/grpc/server"
2222
"github.com/docker/containerd/api/grpc/types"
2323
"github.com/docker/containerd/api/http/pprof"
24+
"github.com/docker/containerd/osutils"
2425
"github.com/docker/containerd/supervisor"
2526
"github.com/docker/docker/pkg/listeners"
2627
"github.com/rcrowley/go-metrics"
@@ -157,6 +158,7 @@ func main() {
157158
func daemon(context *cli.Context) error {
158159
s := make(chan os.Signal, 2048)
159160
signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
161+
osutils.SetSubreaper(1)
160162
sv, err := supervisor.New(
161163
context.String("state-dir"),
162164
context.String("runtime"),

integration-test/start_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"fmt"
55
"os"
6+
"os/exec"
67
"path/filepath"
78
"syscall"
89
"time"
@@ -488,3 +489,50 @@ func swapEnabled() bool {
488489
_, err := os.Stat("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
489490
return err == nil
490491
}
492+
493+
func (cs *ContainerdSuite) TestSigkillShimReuseName(t *check.C) {
494+
bundleName := "busybox-top"
495+
if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
496+
t.Fatal(err)
497+
}
498+
containerID := "top"
499+
c, err := cs.StartContainer(containerID, bundleName)
500+
if err != nil {
501+
t.Fatal(err)
502+
}
503+
504+
// Sigkill the shim
505+
exec.Command("pkill", "-9", "containerd-shim").Run()
506+
507+
// Wait for it to be reaped
508+
for _, evt := range []types.Event{
509+
{
510+
Type: "start-container",
511+
Id: containerID,
512+
Status: 0,
513+
Pid: "",
514+
},
515+
{
516+
Type: "exit",
517+
Id: containerID,
518+
Status: 128 + 9,
519+
Pid: "init",
520+
},
521+
} {
522+
ch := c.GetEventsChannel()
523+
select {
524+
case e := <-ch:
525+
evt.Timestamp = e.Timestamp
526+
527+
t.Assert(*e, checker.Equals, evt)
528+
case <-time.After(2 * time.Second):
529+
t.Fatal("Container took more than 2 seconds to terminate")
530+
}
531+
}
532+
533+
// Start a new continer with the same name
534+
c, err = cs.StartContainer(containerID, bundleName)
535+
if err != nil {
536+
t.Fatal(err)
537+
}
538+
}

runtime/container.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ func (c *container) Delete() error {
253253
args = append(args, "delete", c.id)
254254
if b, derr := exec.Command(c.runtime, args...).CombinedOutput(); err != nil {
255255
err = fmt.Errorf("%s: %q", derr, string(b))
256+
} else if len(b) > 0 {
257+
logrus.Debugf("%v %v: %q", c.runtime, args, string(b))
256258
}
257259
return err
258260
}

runtime/process.go

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"sync"
1313
"syscall"
1414

15+
"github.com/Sirupsen/logrus"
1516
"github.com/docker/containerd/specs"
1617
"golang.org/x/sys/unix"
1718
)
@@ -193,8 +194,58 @@ func (p *process) Resize(w, h int) error {
193194
return err
194195
}
195196

196-
func (p *process) ExitStatus() (int, error) {
197+
func (p *process) handleSigkilledShim(rst int, rerr error) (int, error) {
198+
if rerr == nil || p.cmd == nil || p.cmd.Process == nil {
199+
return rst, rerr
200+
}
201+
202+
// Possible that the shim was SIGKILLED
203+
e := unix.Kill(p.cmd.Process.Pid, 0)
204+
if e != syscall.ESRCH {
205+
return rst, rerr
206+
}
207+
208+
// Ensure we got the shim ProcessState
209+
<-p.cmdDoneCh
210+
211+
shimStatus := p.cmd.ProcessState.Sys().(syscall.WaitStatus)
212+
if shimStatus.Signaled() && shimStatus.Signal() == syscall.SIGKILL {
213+
logrus.Debugf("containerd: ExitStatus(container: %s, process: %s): shim was SIGKILL'ed reaping its child with pid %d", p.container.id, p.id, p.pid)
214+
215+
var (
216+
status unix.WaitStatus
217+
rusage unix.Rusage
218+
wpid int
219+
)
220+
221+
for wpid == 0 {
222+
wpid, e = unix.Wait4(p.pid, &status, unix.WNOHANG, &rusage)
223+
if e != nil {
224+
logrus.Debugf("containerd: ExitStatus(container: %s, process: %s): Wait4(%d): %v", p.container.id, p.id, p.pid, rerr)
225+
return rst, rerr
226+
}
227+
}
228+
229+
if wpid == p.pid {
230+
rerr = nil
231+
rst = 128 + int(shimStatus.Signal())
232+
} else {
233+
logrus.Errorf("containerd: ExitStatus(container: %s, process: %s): unexpected returned pid from wait4 %v (expected %v)", p.container.id, p.id, wpid, p.pid)
234+
}
235+
236+
p.stateLock.Lock()
237+
p.state = Stopped
238+
p.stateLock.Unlock()
239+
}
240+
241+
return rst, rerr
242+
}
243+
244+
func (p *process) ExitStatus() (rst int, rerr error) {
197245
data, err := ioutil.ReadFile(filepath.Join(p.root, ExitStatusFile))
246+
defer func() {
247+
rst, rerr = p.handleSigkilledShim(rst, rerr)
248+
}()
198249
if err != nil {
199250
if os.IsNotExist(err) {
200251
return -1, ErrProcessNotExited

0 commit comments

Comments
 (0)