-
Notifications
You must be signed in to change notification settings - Fork 40k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make kubelet never delete files on mounted filesystems #37698
Make kubelet never delete files on mounted filesystems #37698
Conversation
ba0fa89
to
7444d09
Compare
pkg/util/util.go
Outdated
// files from another filesystems. Like 'rm -rf --one-file-system'. | ||
// It is copied from RemoveAll() sources, with IsLikelyNotMountPoint | ||
func RemoveAllOneFilesystem(mounter mount.Interface, path string) error { | ||
// Simple case: if Remove works, we're done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check mountpoint here, os.Remove can potentially remove dir too
https://golang.org/pkg/os/#Remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
os.Remove() will only remove an empty directory. So it shouldn't work if this is a mountpoint or if it has files in in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the directory was empty and mount point at the same time then we do not remove any user data, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The api contract guarantees nothing about directory emptiness
func Remove(name string) error
Remove removes the named file or directory. If there is an error, it will be of type *PathError.
pkg/util/util.go
Outdated
// Remove contents & return first error. | ||
err = nil | ||
for { | ||
names, err1 := fd.Readdirnames(100) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why 100, not -1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wongma7 that's a question for os.RemoveAll
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, it's reading 100 at a time in the loop.
34cce0f
to
88e47e3
Compare
Unit test added |
88e47e3
to
7573c9c
Compare
7573c9c
to
5ac0bea
Compare
Tested manually with Kubernetes 1.3 with #27653 still reproducible - it does not remove anything in mounted secret (tmpfs) and an AWS volume and shows in the log:
The secret and my AWS volume are still attached and mounted and they're never unmounted (which is fixed in #27653, this PR is just safety check). |
pkg/util/util.go
Outdated
} | ||
|
||
// Close directory, because windows won't remove opened directory. | ||
fd.Close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be worth moving to defer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's a question for os.RemoveAll
5ac0bea
to
3647aa9
Compare
3647aa9
to
73d3e2f
Compare
@jsafrane The main concern of this PR is that adding the os.stat() function in removing directories. In current design, cleanupOrphanedPodDirs is called directly by the main kubelet sync loop, such calls might cause hang problem for cleanup NFS mounted directories. I am not sure if we should consider using separate thread to do the cleanup. |
@jingxu97, |
@jsafrane I see. Another thing I want to check is that before calling RemoveAll() directory, there is a check to see whether there are any volume directories exist. It looks to me this is a strong check already. As long as there is a volume path exist, it will return without removing path. I have an old PR #33616 which tries to check whether there is any mounted directories inside volumes path. Only if the volume path is still mounted, it will skip removing path. Later I removed this logic in #37255 because users complain about NFS hung problem. But as you said, since RemoveAll also call os.Stat(), this check will not add anything worse. |
I think there is not much in the pod directory - there are |
@jsafrane I see. Do you think we should remove the check whether there are directories exist under /volumes? Because I think that check is too strict and might fail to clean up orphaned pods. |
|
@@ -111,7 +111,7 @@ func (kl *Kubelet) cleanupOrphanedPodDirs( | |||
continue | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the we should remove the check len(volumePaths) > 0. If we have this check, any directories exist under /volumes will skip the clean up and RemoveAllOneFilesystem will not be called. The purpose of checking len(volumePaths) > 0 was to prevent any data loss in case the directories under /volumes are not cleaned up properly. Currently, it is possible that the directories under /volumes are unmounted, but fail to delete. If this happens, cleanupOrphanedPod will fail to delete the pod directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm |
@k8s-bot test this |
@thockin, please approve |
It would be nice to have a benchmark on this vs plain old RemoveAll. |
@k8s-bot verify test this A batch test failed indicating that this needs a staging client-go update. |
With bug kubernetes#27653, kubelet could remove mounted volumes and delete user data. The bug itself is fixed, however our trust in kubelet is significantly lower. Let's add an extra version of RemoveAll that does not cross mount boundary (rm -rf --one-file-system). It calls lstat(path) three times for each removed directory - once in RemoveAllOneFilesystem and twice in IsLikelyNotMountPoint, however this way it's platform independent and the directory that is being removed by kubelet should be almost empty.
02741e5
to
d7d039d
Compare
I moved the function to standalone package at
|
[APPROVALNOTIFIER] This PR is NOT APPROVED The following people have approved this PR: jingxu97, jsafrane, k8s-merge-robot Needs approval from an approver in each of these OWNERS Files: We suggest the following people: |
Automatic merge from submit-queue (batch tested with PRs 41139, 41186, 38882, 37698, 42034) |
Will the issue be merge into the v1.6.5 version of Kubernetes? |
@jsafrane We are using a cluster of Kubernetes v1.3.4 with 50+ nodes. We've found an issue that the Kubelet will automatically delete all NFS mounted files after the POD became to orphan. This Issue JUST likes what problem we met, so I really care about the BUG FIX about that. I have no way to prove that the version of v1.6.4 Kubelet won't deletes the mounted files again. |
@g0194776 the fix is in 1.3 branch starting only with 1.3.6 https://github.com/kubernetes/kubernetes/releases/tag/v1.3.6. The fix is definitely in 1.6.4 |
As jsafrane said the real bug fix is #27970
<#27970> and that's what I
mean when I say "the fix." If you insist on getting this patch as well then
it needs to be backported because like he said, nobody asked for it until
now. Does that make sense?
…On Thu, Jun 22, 2017 at 8:30 AM, Kevin Yang ***@***.***> wrote:
@wongma7 <https://github.com/wongma7> Obviously, It does not fix YET. I
was checking the source code of v1.6.4 out on few days ago, I also checked
the code implementation at here.
<https://github.com/kubernetes/kubernetes/blob/v1.6.4/pkg/kubelet/kubelet_volumes.go#L118>
The newest change JUST replaces *os.RemoveAll* to another method which
called: "removeall.RemoveAllOneFilesystem".
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#37698 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AMgP-Isvrtq4Hfe5pQPBknSKaH-CjmW4ks5sGl5VgaJpZM4LAakP>
.
|
@wongma7 Okay, I got it. |
With bug #27653, kubelet could remove mounted volumes and delete user data.
The bug itself is fixed, however our trust in kubelet is significantly lower.
Let's add an extra version of RemoveAll that does not cross mount boundary
(rm -rf --one-file-system).
It calls lstat(path) three times for each removed directory - once in
RemoveAllOneFilesystem and twice in IsLikelyNotMountPoint, however this way
it's platform independent and the directory that is being removed by kubelet
should be almost empty.