mirror of
https://github.com/containers/podman.git
synced 2025-05-17 15:18:43 +08:00
move rootless netns slirp4netns process to systemd user.slice
When running podman inside systemd user units, it is possible that systemd kills the rootless netns slirp4netns process because it was started in the default unit cgroup. When the unit is stopped all processes in that cgroup are killed. Since the slirp4netns process is run once for all containers it should not be killed. To make sure systemd will not kill the process we move it to the user.slice. Fixes #13153 Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:

committed by
Matthew Heon

parent
7e37c608f7
commit
ed60f89086
@ -28,6 +28,7 @@ import (
|
||||
"github.com/containers/podman/v4/pkg/resolvconf"
|
||||
"github.com/containers/podman/v4/pkg/rootless"
|
||||
"github.com/containers/podman/v4/pkg/util"
|
||||
"github.com/containers/podman/v4/utils"
|
||||
"github.com/containers/storage/pkg/lockfile"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
@ -495,6 +496,12 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// move to systemd scope to prevent systemd from killing it
|
||||
err = utils.MoveRootlessNetnsSlirpProcessToUserSlice(cmd.Process.Pid)
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to move the rootless netns slirp4netns process to the systemd user.slice: %v", err)
|
||||
}
|
||||
|
||||
// build a new resolv.conf file which uses the slirp4netns dns server address
|
||||
resolveIP, err := GetSlirp4netnsDNS(nil)
|
||||
if err != nil {
|
||||
|
@ -281,4 +281,34 @@ LISTEN_FDNAMES=listen_fdnames" | sort)
|
||||
is "$output" "" "output should be empty"
|
||||
}
|
||||
|
||||
# https://github.com/containers/podman/issues/13153
|
||||
@test "podman rootless-netns slirp4netns process should be in different cgroup" {
|
||||
is_rootless || skip "only meaningful for rootless"
|
||||
|
||||
cname=$(random_string)
|
||||
local netname=testnet-$(random_string 10)
|
||||
|
||||
# create network and container with network
|
||||
run_podman network create $netname
|
||||
run_podman create --name $cname --network $netname $IMAGE top
|
||||
|
||||
# run container in systemd unit
|
||||
service_setup
|
||||
|
||||
# run second container with network
|
||||
cname2=$(random_string)
|
||||
run_podman run -d --name $cname2 --network $netname $IMAGE top
|
||||
|
||||
# stop systemd container
|
||||
service_cleanup
|
||||
|
||||
# now check that the rootless netns slirp4netns process is still alive and working
|
||||
run_podman unshare --rootless-netns ip addr
|
||||
is "$output" ".*tap0.*" "slirp4netns interface exists in the netns"
|
||||
run_podman exec $cname2 nslookup google.com
|
||||
|
||||
run_podman rm -f -t0 $cname2
|
||||
run_podman network rm -f $netname
|
||||
}
|
||||
|
||||
# vim: filetype=sh
|
||||
|
@ -174,7 +174,7 @@ func RunsOnSystemd() bool {
|
||||
return runsOnSystemd
|
||||
}
|
||||
|
||||
func moveProcessToScope(pidPath, slice, scope string) error {
|
||||
func moveProcessPIDFileToScope(pidPath, slice, scope string) error {
|
||||
data, err := ioutil.ReadFile(pidPath)
|
||||
if err != nil {
|
||||
// do not raise an error if the file doesn't exist
|
||||
@ -187,18 +187,32 @@ func moveProcessToScope(pidPath, slice, scope string) error {
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot parse pid file %s", pidPath)
|
||||
}
|
||||
err = RunUnderSystemdScope(int(pid), slice, scope)
|
||||
|
||||
return moveProcessToScope(int(pid), slice, scope)
|
||||
}
|
||||
|
||||
func moveProcessToScope(pid int, slice, scope string) error {
|
||||
err := RunUnderSystemdScope(int(pid), slice, scope)
|
||||
// If the PID is not valid anymore, do not return an error.
|
||||
if dbusErr, ok := err.(dbus.Error); ok {
|
||||
if dbusErr.Name == "org.freedesktop.DBus.Error.UnixProcessIdUnknown" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// MoveRootlessNetnsSlirpProcessToUserSlice moves the slirp4netns process for the rootless netns
|
||||
// into a different scope so that systemd does not kill it with a container.
|
||||
func MoveRootlessNetnsSlirpProcessToUserSlice(pid int) error {
|
||||
randBytes := make([]byte, 4)
|
||||
_, err := rand.Read(randBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return moveProcessToScope(pid, "user.slice", fmt.Sprintf("rootless-netns-%x.scope", randBytes))
|
||||
}
|
||||
|
||||
// MovePauseProcessToScope moves the pause process used for rootless mode to keep the namespaces alive to
|
||||
// a separate scope.
|
||||
func MovePauseProcessToScope(pausePidPath string) {
|
||||
@ -211,7 +225,7 @@ func MovePauseProcessToScope(pausePidPath string) {
|
||||
logrus.Errorf("failed to read random bytes: %v", err)
|
||||
continue
|
||||
}
|
||||
err = moveProcessToScope(pausePidPath, "user.slice", fmt.Sprintf("podman-pause-%x.scope", randBytes))
|
||||
err = moveProcessPIDFileToScope(pausePidPath, "user.slice", fmt.Sprintf("podman-pause-%x.scope", randBytes))
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
Reference in New Issue
Block a user