Skip to content

Instantly share code, notes, and snippets.

@jb-alvarado
Last active March 18, 2024 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jb-alvarado/2ef1645e06859f7d04e2b2258b02689d to your computer and use it in GitHub Desktop.
Save jb-alvarado/2ef1645e06859f7d04e2b2258b02689d to your computer and use it in GitHub Desktop.
Add poddman container to existing host bridge
#!/usr/bin/bash
# This script manages network interfaces for Podman containers. Podman is a daemonless container engine
# for developing, managing, and running OCI Containers on your Linux System.
#
# The script takes three arguments: an operation (either "start" or "stop"), a container name, and an IPv4
# address for the container. If any of these arguments are missing, the script will exit with an error message.
#
# The script first checks if it's being run as root. If not, it prepends `sudo` to certain commands to ensure
# they have the necessary permissions.
#
# The script then sets up some variables, including the bridge interface name (`br0`), the IPv4 address with
# a subnet mask (`ipv4`), the virtual Ethernet device ID (`veth_id`), the virtual Ethernet device name
# (`veth_dev`), the gateway IP address (`gate`), and the container interface name (`cont_iface`).
#
# The script then retrieves the full container ID using the `podman inspect` command and constructs a network
# namespace name from it.
#
# If the operation is "start", the script starts the container, creates a directory for network namespaces
# if it doesn't exist, retrieves the container's PID, and creates a symlink from the container's network
# namespace to a file in the `/var/run/netns` directory. It then creates a virtual Ethernet device, attaches
# it to the bridge, moves the peer interface to the container's network namespace, renames the peer interface,
# brings up both interfaces, assigns the IPv4 address to the container's interface, and adds a default route
# in the container's network namespace.
#
# If the operation is "stop", the script removes the default route in the container's network namespace,
# removes the IPv4 address from the container's interface, brings down both interfaces, stops the container,
# and removes the symlink to the container's network namespace.
#
# This script is a example of how to manually manage network interfaces for containers when you need more #
# control than the default networking provided by container runtimes.
#
# The idea to this script comes from podman network documentation:
# https://github.com/containers/podman/blob/main/docs/tutorials/performance.md#network-performance-for-rootless-podman
# and a podman list post from Rudolf Vesely:
# https://lists.podman.io/archives/list/podman@lists.podman.io/thread/W6MCYO6RY5YFRTSUDAOEZA7SC2EFXRZE/
# start / stop
operation=$1
# container name
container=$2
# container ip v4
cont_ip4=$3
SUDO=""
if [[ -z "$operation" ]] || [[ -z "$container" ]] || [[ -z "$cont_ip4" ]]; then
echo "Run command with 'start/stop' 'container name' 'IP'!"
exit 1
fi
# when not runniing as root, for rootful containers,
# run system commands with sudo, for footless container.
if (( $EUID != 0 )); then
SUDO="sudo"
fi
bridge="br0"
ipv4="${cont_ip4}/24"
veth_id="$(echo -n "$cont_ip4" | tail -c 2 | sed 's/.//g')"
veth_id="$(printf "%02d" $veth_id)"
veth_dev="veth3${veth_id}"
gate="10.10.0.1"
cont_iface="eth0"
# container need to be created with no network interface:
# podman run --net=none ...
# get full container ID
cont_id=$(podman inspect -f '{{.Id}}' $container)
net_ns_name="cont-${cont_id}"
if [[ $operation == "start" ]]; then
podman start $container
# create folder if not exists
[[ ! -d /var/run/netns ]] && $SUDO mkdir -v /var/run/netns
# get container pid, works only on running containers
cont_pc_id=$(podman inspect -f '{{.State.Pid}}' "${cont_id}")
# symlink container pid to container name id
$SUDO ln -sfT "/proc/${cont_pc_id}/ns/net" "/var/run/netns/${net_ns_name}"
# create virtual interface on existing bridge interface
# start interface and add default route
$SUDO ip link add $veth_dev type veth peer name veth300p
$SUDO ip link set dev $veth_dev master $bridge
$SUDO ip link set veth300p netns "$net_ns_name"
$SUDO ip -netns "$net_ns_name" link set veth300p name "$cont_iface"
$SUDO ip link set dev $veth_dev up
$SUDO ip -netns "$net_ns_name" link set dev "$cont_iface" up
$SUDO ip -netns "$net_ns_name" address add "$ipv4" dev "$cont_iface"
$SUDO ip -netns "$net_ns_name" route add default via "$gate"
elif [[ $operation == "stop" ]]; then
# remove route and virtual interface
$SUDO ip -netns "$net_ns_name" route del default via "$gate"
$SUDO ip -netns "$net_ns_name" address del "$ipv4" dev "$cont_iface"
$SUDO ip -netns "$net_ns_name" link set dev "$cont_iface" down
$SUDO ip link set dev $veth_dev down
podman stop $container
$SUDO rm -f "/var/run/netns/$net_ns_name"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment