fix: prevent EBUSY when unmounting system disk

Reading /proc/mounts while simultaneously unmounting mountpoints
prevents unmounting all submounts under /var. This is due to the fact
that /proc/mounts will change as we perform unmounts, and that causes a
read of the file to become inaccurate. We now read /proc/mounts into
memory to get a snapshot of all submounts under /var, and then we
proceed with unmounting them.

This also adds some additional logging that I found to be useful while
debugging this. It also adds logic to skip of DaemonSet managed pods.

Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
Andrew Rynhard
2019-09-06 06:20:05 +00:00
parent f03975bdc3
commit 37a8ce78ae
3 changed files with 22 additions and 8 deletions

View File

@@ -6,6 +6,7 @@ package kubernetes
import ( import (
"context" "context"
"log"
"syscall" "syscall"
"github.com/containerd/containerd" "github.com/containerd/containerd"
@@ -59,6 +60,7 @@ func (task *KillKubernetesTasks) standard() (err error) {
for _, task := range response.Tasks { for _, task := range response.Tasks {
task := task // https://golang.org/doc/faq#closures_and_goroutines task := task // https://golang.org/doc/faq#closures_and_goroutines
log.Printf("killing task %s", task.ID)
g.Go(func() error { g.Go(func() error {
if _, err = s.Kill(ctx, &tasks.KillRequest{ContainerID: task.ID, Signal: uint32(syscall.SIGTERM), All: true}); err != nil { if _, err = s.Kill(ctx, &tasks.KillRequest{ContainerID: task.ID, Signal: uint32(syscall.SIGTERM), All: true}); err != nil {
return errors.Wrap(err, "error killing task") return errors.Wrap(err, "error killing task")

View File

@@ -6,7 +6,9 @@ package rootfs
import ( import (
"bufio" "bufio"
"os" "bytes"
"io/ioutil"
"log"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -37,14 +39,14 @@ func (task *UnmountPodMounts) RuntimeFunc(mode runtime.Mode) phase.RuntimeFunc {
} }
func (task *UnmountPodMounts) standard(platform platform.Platform, data *userdata.UserData) (err error) { func (task *UnmountPodMounts) standard(platform platform.Platform, data *userdata.UserData) (err error) {
file, err := os.Open("/proc/mounts") var b []byte
if err != nil { if b, err = ioutil.ReadFile("/proc/self/mounts"); err != nil {
return err return err
} }
// nolint: errcheck
defer file.Close()
scanner := bufio.NewScanner(file) r := bytes.NewReader(b)
scanner := bufio.NewScanner(r)
for scanner.Scan() { for scanner.Scan() {
fields := strings.Fields(scanner.Text()) fields := strings.Fields(scanner.Text())
@@ -54,11 +56,15 @@ func (task *UnmountPodMounts) standard(platform platform.Platform, data *userdat
mountpoint := fields[1] mountpoint := fields[1]
if strings.HasPrefix(mountpoint, constants.EphemeralMountPoint+"/") { if strings.HasPrefix(mountpoint, constants.EphemeralMountPoint+"/") {
if err := unix.Unmount(mountpoint, 0); err != nil { log.Printf("unmounting %s\n", mountpoint)
return errors.Errorf("error creating overlay mount to %s: %v", mountpoint, err) if err = unix.Unmount(mountpoint, 0); err != nil {
return errors.Errorf("error unmounting %s: %v", mountpoint, err)
} }
} }
} }
if err = scanner.Err(); err != nil {
return err
}
return nil return nil
} }

View File

@@ -104,6 +104,12 @@ func (h *Helper) Drain(node string) error {
for _, pod := range pods.Items { for _, pod := range pods.Items {
go func(p corev1.Pod) { go func(p corev1.Pod) {
defer wg.Done() defer wg.Done()
for _, ref := range p.ObjectMeta.OwnerReferences {
if ref.Kind == "DaemonSet" {
log.Printf("skipping DaemonSet pod %s\n", p.GetName())
return
}
}
if err := h.evict(p, int64(60)); err != nil { if err := h.evict(p, int64(60)); err != nil {
log.Printf("WARNING: failed to evict pod: %v", err) log.Printf("WARNING: failed to evict pod: %v", err)
} }