Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/nerdctl/container/container_run_network_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -838,8 +838,8 @@ func TestHostsFileMounts(t *testing.T) {
}

func TestRunContainerWithStaticIP6(t *testing.T) {
if rootlessutil.IsRootless() {
t.Skip("Static IP6 assignment is not supported rootless mode yet.")
if rootlessutil.IsRootless() && !rootlessutil.RootlessKitIPv6Enabled() {
t.Skip("Rootless IPv6 requires CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6=true; see docs/rootless.md")
}
networkName := "test-network"
networkSubnet := "2001:db8:5::/64"
Expand Down
5 changes: 5 additions & 0 deletions docs/rootless.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ Rootless containerd recognizes the following environment variables to configure
the host loopback IP address (127.0.0.1) and abstract sockets are exposed to Dockerfile's "RUN" instructions during `nerdctl build` (not `nerdctl run`).
The drawback is fixed in BuildKit v0.13. Upgrading from a prior version of BuildKit needs removing the old systemd unit:
`containerd-rootless-setuptool.sh uninstall-buildkit && rm -f ~/.config/buildkit/buildkitd.toml`
* `CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6=(true|false)`: whether to enable IPv6 inside the RootlessKit network namespace.
Defaults to "false". After enabling this, create IPv6-capable CNI networks with
`nerdctl network create --ipv6 --subnet <v6-subnet>` as usual. Published ports over IPv6 are
supported with `--port-driver=builtin` (the default). `--port-driver=slirp4netns` does not yet
Comment thread
Akshitguptaa marked this conversation as resolved.
Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work with pasta too? (--net=pasta --port-driver=implicit)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this with pasta and --port-driver=implicit, but it currently fails during port exposure with no PortDriver is available. It looks like nerdctl's rootless-port hook expects the PortDriver API to be active when -p is passed, which isn't the case under implicit.

I've updated the docs in 5e18ed0 to explicitly note that pasta isn't supported for IPv6 port forwarding yet.

support IPv6 port forwarding upstream.

To set these variables, create `~/.config/systemd/user/containerd.service.d/override.conf` as follows:
```ini
Expand Down
23 changes: 23 additions & 0 deletions extras/rootless/containerd-rootless.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
# the host loopback IP address (127.0.0.1) and abstract sockets are exposed to Dockerfile's "RUN" instructions during `nerdctl build` (not `nerdctl run`).
# The drawback is fixed in BuildKit v0.13. Upgrading from a prior version of BuildKit needs removing the old systemd unit:
# `containerd-rootless-setuptool.sh uninstall-buildkit && rm -f ~/.config/buildkit/buildkitd.toml`
# * CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6=(true|false): whether to enable IPv6 inside the RootlessKit network namespace.
# Defaults to "false". Requires a RootlessKit network driver that supports IPv6 (slirp4netns >= v0.4.0 with an
# IPv6-capable build). When using `--port-driver=slirp4netns`, published ports over IPv6 additionally require
# IPv6 support in slirp4netns's port driver, which is not yet available upstream
# (see https://github.com/rootless-containers/slirp4netns/pull/276).
Comment thread
Akshitguptaa marked this conversation as resolved.
Outdated

# See also: https://github.com/containerd/nerdctl/blob/main/docs/rootless.md#configuring-rootlesskit

Expand Down Expand Up @@ -78,6 +83,7 @@ if [ -z "$_CONTAINERD_ROOTLESS_CHILD" ]; then
: "${CONTAINERD_ROOTLESS_ROOTLESSKIT_SLIRP4NETNS_SANDBOX:=auto}"
: "${CONTAINERD_ROOTLESS_ROOTLESSKIT_SLIRP4NETNS_SECCOMP:=auto}"
: "${CONTAINERD_ROOTLESS_ROOTLESSKIT_DETACH_NETNS:=auto}"
: "${CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6:=false}"
net=$CONTAINERD_ROOTLESS_ROOTLESSKIT_NET
mtu=$CONTAINERD_ROOTLESS_ROOTLESSKIT_MTU
if [ -z "$net" ]; then
Expand Down Expand Up @@ -137,6 +143,23 @@ if [ -z "$_CONTAINERD_ROOTLESS_CHILD" ]; then
;;
esac

case "$CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6" in
1 | true)
if ! rootlesskit --help | grep -qw -- "--ipv6"; then
echo "CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6=true requires a RootlessKit build that supports --ipv6"
Comment thread
Akshitguptaa marked this conversation as resolved.
Outdated
exit 1
fi
CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS="--ipv6 $CONTAINERD_ROOTLESS_ROOTLESSKIT_FLAGS"
;;
0 | false)
# NOP
;;
*)
echo "Unknown CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6 value: $CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6"
exit 1
;;
esac

# Re-exec the script via RootlessKit, so as to create unprivileged {user,mount,network} namespaces.
#
# --copy-up allows removing/creating files in the directories by creating tmpfs and symlinks
Expand Down
9 changes: 9 additions & 0 deletions hack/test-integration-rootless.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ if [ ! -e "$HOME/.config/nerdctl-test-setup-done" ]; then
systemctl --user daemon-reload
fi

if [ "${CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6:-false}" = "true" ]; then
Comment thread
Akshitguptaa marked this conversation as resolved.
mkdir -p "$HOME/.config/systemd/user/containerd.service.d"
cat <<-EOF >"$HOME/.config/systemd/user/containerd.service.d/ipv6.conf"
[Service]
Environment="CONTAINERD_ROOTLESS_ROOTLESSKIT_IPV6=true"
EOF
systemctl --user daemon-reload
fi

containerd-rootless-setuptool.sh install
if grep -q "options use-vc" /etc/resolv.conf; then
containerd-rootless-setuptool.sh nsenter -- sh -euc 'echo "options use-vc" >>/etc/resolv.conf'
Expand Down
23 changes: 23 additions & 0 deletions pkg/rootlessutil/rootlessutil_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package rootlessutil

import (
"bytes"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -119,3 +120,25 @@ func WithDetachedNetNSIfAny(fn func() error) error {
}
return ns.WithNetNSPath(netns, func(_ ns.NetNS) error { return fn() })
}

// RootlessKitIPv6Enabled reports whether the running RootlessKit parent process was launched with --ipv6.
func RootlessKitIPv6Enabled() bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks that is a better approach

I've opened rootless-containers/rootlesskit#607 to add the IPv6 boolean to NetworkDriverInfo

could you take a look at that pr when you have a chance?
once that is merged, I can update this logic as well and we can get this PR merged as well.

@AkihiroSuda AkihiroSuda Jul 9, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving this to testutil pkg

stateDir, err := RootlessKitStateDir()
if err != nil {
return false
}
pid, err := RootlessKitChildPid(stateDir)
if err != nil {
return false
}
cmdline, err := os.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "cmdline"))
if err != nil {
return false
}
for _, arg := range bytes.Split(cmdline, []byte{0}) {
if string(arg) == "--ipv6" {
return true
}
}
return false
}
Loading