Proxy ports into a running Docker(-Compose) container

Publishing ports in Docker is done only once at the beginning on the creation of the container. Yet sometimes there is the need to talk to the service inside a container, but the container itself does not have the proper tools to do what you want with it built-in. Yet re-creating the container just to publish the ports, maybe manifesting it temporarily in some docker-compose.yml, and then forgetting about it to open up some security problem is not great.

So the following script allows to temporally proxy to a port of a running container, whether for manually ran containers or the ones in a network from Docker-Compose. It tries to find the network and attaches to it, unless it's bridge, and uses a socat to run the proxy. The arguments are the container name or ID, the port to proxy to, and an optional port where to publish (if not given, Docker will pick one).

#!/bin/sh

set -eu

if test ! "$#" -ge 2; then
    echo "$0 <container> <target_port> (<local_port>)"
    exit 1
fi

container="$1"
port="$2"

network=$(docker inspect --format '{{range $k,$v:= .NetworkSettings.Networks}}{{println $k}}{{end}}' "$container" | head -n1)

inner_port=8080
publish="$inner_port"
if test "$#" -ge 3; then
    publish="$3:$publish"
fi

docker run \
    --rm \
    --publish="$publish" \
    --link="$container:target" \
    $(if test "$network" != "bridge"; then echo "--network=$network"; fi) \
    alpine/socat \
        "tcp-listen:$inner_port,fork,reuseaddr" \
        "tcp-connect:target:$port"