-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Try to use pidfd and epoll to wait init process exit #4517
base: main
Are you sure you want to change the base?
Conversation
bcddc62
to
8126a8d
Compare
@abel-von PTAL |
It seems that the first commit can be merged now and is definitely an improvement. For the rest of it, give me a few days to review. |
Reviewing this reminded me the next step needed for pidfd support in Go, so I wrote this proposal: golang/go#70352 |
Wonderful proposal, I used to think that golang wouldn't support similar interfaces, but I think it's very useful, looking forward its coming. |
8126a8d
to
7833912
Compare
libcontainer/container_linux.go
Outdated
return errors.New("container init still running") | ||
} | ||
|
||
// Kill kills the container and wait the init process exit. |
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.
... and waits for the init process to exit.
libcontainer/container_linux.go
Outdated
|
||
events := make([]unix.EpollEvent, 1) | ||
for { | ||
// Set the timeout to 10s, the same as the traditional unix.Signal solution. |
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 same as in kill below
delete.go
Outdated
if !container.Config().Namespaces.IsPrivate(configs.NEWPID) { | ||
return killContainer(container) | ||
} | ||
return container.Destroy() |
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.
Maybe drop killContainer
entirely here and just call container.Kill()
and then container.Destroy()
? The code is more readable this way.
Or, rename killContainer to killAndDestroy.
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.
Maybe drop
killContainer
entirely here and just callcontainer.Kill()
and thencontainer.Destroy()
? The code is more readable this way.
Good idea, it is indeed more readable than before!
LGTM |
@lifubang are you going to keep working on it? This looks very good overall |
Thanks, I'll work on it later. |
Because we should switch to unix.PidFDSendSignal in new kernels, it has been supported in go runtime. We don't need to add fall back to unix.Kill code here. Signed-off-by: lfbzhm <[email protected]>
Signed-off-by: lfbzhm <[email protected]>
7833912
to
cc64599
Compare
When using unix.Kill to kill the container, we need a for loop to detect the init process exited or not manually, we sleep 100ms each time in the current, but for stopped containers or containers running in a low load machine, we don't need to wait so long time. This change will reduce the delete delay in some situations, especially for those pods with many containers in. Co-authored-by: Abel Feng <[email protected]> Signed-off-by: lfbzhm <[email protected]>
cc64599
to
16ae7fc
Compare
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.
Frankly, I'm having a hard time reviewing this because it's hard to wrap around all the kill/destroy logic that we already have in place:
container.Signal
;terminate
method ofparentProcess
;destroy(c *Container)
;- etc.
All this seem like a bunch of code full of special cases and kludges, and (in my eyes) it cries to be refactored to be more straightforward and clean. Maybe I'm wrong but this stands in the way of me reviewing this.
As I can't finish this, here's my WIP review bits and pieces:
-
The logic added might also be useful from
func destroy(c *Container) error
. -
Using epoll on pidfd can also be used when there are multiple pids (i.e. from signalAllProcesses, in the current code).
-
This adds a new public method (
container.Kill
) when we already havecontainer.Signal
. I understand why, but maybe we should call itcontainer.KillSync
(orcontainer.EnsureKilled
) instead (so it's clear it not just sends the SIGKILL but also waits for the container to be killed). A note tocontainer.Signal
should be added referencing the new method. It should also be described in libcontainer's README.
This PR does some optimizations for
runc delete -f
.unix.PidFDSendSignal
to send signal to the process,this is helpful to reduce the risk of pid reuse attack. So we should replace
unix.Kill
withos.Process.Signal
in runc when possible.os.Process.Wait
is used to wait the child process, to wait a unrelated process, weshould introduce pidfd & epoll to reduce the sleep time when we want to detect the init
process exited or not.
unix.Kill
solution, but for stopped containers or containers running in a low load machine,we don't need to wait 100ms to do the next detection.
Close: #4512