-
Notifications
You must be signed in to change notification settings - Fork 654
fix: clean up iptables rules for stopped containers #4255
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
fix: clean up iptables rules for stopped containers #4255
Conversation
It does not feel like this would fix #4253 or any of the same ilk, or will it? |
Also be sure to check out: #3357 In case of failure during onCreateRuntime, onPostStop is either wrongly dispatched while the container is not deleted, or the container should have been deleted but is not. Your post-cleanup here (while useful for "normal" exits) will not work in case of failures onCreateRuntime because of ^ |
Suggestion is:
Then we might want to have a look overall at what we do in oci hooks. |
SGTM,
|
The original PR has been opened over two years ago. |
b05e3af
to
06bc982
Compare
e4d1795
to
20e3c2f
Compare
d01cafd
to
5eca797
Compare
// TestContainerRmIptables tests that iptables rules are cleared after container deletion | ||
func TestContainerRmIptables(t *testing.T) { | ||
if _, err := exec.LookPath("iptables"); err != nil { | ||
t.Skip("iptables command not found, skipping test") |
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.
testCase.Require
should be used to require the command
testCase := nerdtest.Setup() | ||
|
||
// This test requires Linux | ||
testCase.Require = require.Not(require.Windows) |
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 test is meaningless on Docker?
} | ||
|
||
// In non-rootless mode, check iptables rules directly on the host | ||
return helpers.Custom("sh", "-c", "iptables -t nat -S && iptables -t filter -S && iptables -t mangle -S") |
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 shell script should be defined as a constant to avoid the code clone across rootless and rootful
220d43d
to
be7756c
Compare
99d989e
to
1176445
Compare
@AkihiroSuda @apostasie PTAL |
Description: "Test iptables rules are cleared after container deletion", | ||
Setup: func(data test.Data, helpers test.Helpers) { | ||
// Create a container with port mapping to ensure iptables rules are created | ||
helpers.Ensure("run", "-d", "--name", data.Identifier(), "-p", "8080:80", testutil.NginxAlpineImage) |
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.
8080 may (is) shared by many compose tests, so, presents a risk of colliding port between parallelized tests (once we do parallelize more of them).
port, err = portlock.Acquire(0)
and (during cleanup) portlock.Release
would help ensuring we get a free port (since we are not specifically committed to 8080).
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.
fixed
container := nerdtest.InspectContainer(helpers, data.Identifier()) | ||
containerID = container.ID | ||
data.Labels().Set("containerID", containerID) | ||
} |
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 would just move this section above to Setup
, just after container creation - then you would not need to test that the label is empty. I would even call helpers.Capture
instead of helpers.Ensure
, so that you get the id directly instead of having to Inspect
.
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.
fixed
@@ -479,6 +480,15 @@ func applyNetworkSettings(opts *handlerOpts) error { | |||
if err != nil { | |||
return fmt.Errorf("failed to call cni.Setup: %w", err) | |||
} | |||
|
|||
// Defer CNI configuration removal to ensure idempotency of oci-hook. | |||
defer func() { |
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 am now wondering if this should be moved above opts.cni.Setup
? (eg: would there be conditions where cni setup would fail and leave partially configured network above?)
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.
fixed
@fahedouch couple of non critical nits:
Anyhow, LGTM - let's have this in, it is a big deal. |
t.Fatalf("Failed to get detached network namespace: %v", err) | ||
} else { | ||
if netns != "" { | ||
// First enter the user and mount namespace, then the network namespace |
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.
Probably you can use containerd-rootless-setuptool.sh nsenter -- nsenter --net=...
to simplify the code
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.
fixed
|
||
// Construct the path to the network namespace | ||
uid := os.Getuid() | ||
netnsPath := fmt.Sprintf("/run/user/%d/containerd-rootless/netns", uid) |
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.
This variable is redundant. The path is provided in the netns
string below
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.
fixed
1176445
to
3cea6c8
Compare
if netns != "" { | ||
// Use containerd-rootless-setuptool.sh to enter the RootlessKit namespace | ||
return helpers.Custom("containerd-rootless-setuptool.sh", "nsenter", "--", "sh", "-c", | ||
fmt.Sprintf("nsenter --net=%s sh -c '%s'", netns, iptablesCheckCommand)) |
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.
No need to use sh -c
twice.
The first one can be replaced with "c-r-s.sh", "nsenter", "--", "nsenter", "--net="+netns, ...
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.
Also probably sh -c
should be sh -ec
for _, rule := range rules { | ||
if strings.Contains(rule, containerID) { | ||
// Execute delete command | ||
deleteCmd := exec.Command("sh", "-c", "--", fmt.Sprintf(`iptables -t %s -D %s`, table, rule[3:])) |
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.
No need to use sh -c
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 need to pass string cmd with sh -c
to avoid escaping issues. see #4255 (comment)
…eletion Signed-off-by: fahed dorgaa <[email protected]>
3cea6c8
to
e9ac446
Compare
// Remove the container | ||
helpers.Ensure("rm", "-f", containerID) | ||
|
||
time.Sleep(1 * time.Second) |
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.
Curious if this is necessary. Is cni teardown going to be asynchronous?
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.
Thanks
fixing this issue #1872 or at least a part of the issue
Based on the runtime-spec documentation, the post-hook is executed after the container task is deleted. This ensures that resources are properly cleaned up when the container is removed, allowing sufficient iptables space for the next container to be created.
I think this should replace #4254 ( cc @apostasie)