External via VPN does not allow for internal MySQL connection?

I have made a docker-compose file with 3 container:

  1. gluetun for VPN connection
  2. mysql for my database
  3. python for my python script.

So my python script needs to take and store from my mysql container and perform tasks via the gluetun VPN connection on the external Internet.

I fail to get my python script to connect to my mysql database.

How to setup the docker-compose.yml to get this workign correctly?

On my python service I have network_mode: “service:gluetun” and indeed my python script uses the VPN correctly.

Connecting to mysql fails:

try:
            db = mysql.connect(
                host = os.getenv('DB_HOST', 'mysql'),  # Default to 'mysql' instead of 'localhost'
                user = os.getenv('DB_USER'),
                passwd = os.getenv('DB_PASSWORD'),
                database = os.getenv('DB_NAME', 'ftpspider_db')
            )
            return db
except mysql.Error as err:
            print(f"Failed to connect to MySQL ({i+1}/{max_retries}). Retrying...")

In the mysql service in the docker-compose, I have: container_name: mysql. I can also connect DBeaver to my mysql database without problems.

I have no other network settings in my docker-compose file.

I do understand that my python script now connects to gluetun. I do not understand how to set it up in a way that for local containers it goes directly…

Services/containers in Docker compose automatically use an implicit shared Docker network. Internal Docker DNS resolves Docker service names to the internal IPs.

A service that declares a network_mode can not declare networks, though the gluetun container can. The glutan service needs to share a container network with the database, in order to allow a container that is created with network_mode: "service:gluetan" to access the database container.

I manged to find a solution by:

  • All containers: network_mode: “service:gluetun”
  • Exposing port 3306 in Gluetun (VPN)

However, to me it now looks that all python-mysql traffic goes through the gluetun container. Shouldn’t that go directly? Or am I misunderstanding the network_mode?

You basically make gluetan share its network namespace with other container, which join its network namespace and therefor use all existing network interfaces tat the gluetan container has.

Since no container, except the gluetan container has its own network interfaces, I am not sure what you mean by “Shouldn’t that go directly?” All the containers can communicate with each other using localhost (which wouldn’t work without network_mode: "service:gluetan").

I guess it is indeed my understanding on how this networking things works. I got confused by the comment I got from ChatGPT (4o) about this: “Downside: You can’t access MySQL externally anymore (unless Gluetun exposes it, which is messy).”. So it told me the better alternative is to Remove network_mode: "service:gluetun" from my python container and instead , use a custom Docker network, and set python to use Gluetun as its default gateway via --net/--ip tricks or a network_mode: "service:gluetun" only for outbound, while still keeping access to local containers.

As I now understand, network_mode: “service:gluetan” and exposing port 3306 is just fine.

Is it really messy, if you intentionally attach other containers to the network namespace of a container?

The behavior kind of resembles how it is with Kubernetes pods, with the difference that in Kubernetes the pod owns the network namespace, and the main and sidecar containers share network namespace of the pod.

.