Docker Multi App Networking
Services in one Compose file reach each other by their service names. Services in different applications don’t, even on the same deployment target, because the Docker controller runs every deployment as a Compose project of its own (distr-<short-deployment-id>) with its own default network.
To connect them, one application creates a Docker network and the others join it. The example at the end does this for a database and a backend that are deployed separately.
Step 1: Create the network application
Section titled “Step 1: Create the network application”Create a Docker application in Distr with the following Compose file. It exists only to create the shared network.
services: network: image: 'registry.k8s.io/pause:3.10' restart: unless-stopped networks: - acme-shared
networks: acme-shared: name: acme-sharednetworks.acme-shared.namefixes the network’s name. Without it, Compose puts the project name in front. That name differs for every deployment, so the others would not find the network. Replaceacme-sharedwith a name unique to your application.networkis a placeholder. Compose won’t start a project that has no services, so the application needs one. Thepauseimage does nothing and uses almost no resources.
One of your other applications can create the network too, the way the proxy does in Docker Blue-Green Deployments. The advantage of a separate application is that you can update or undeploy any of the others without touching the network.
Step 2: Join the network from your applications
Section titled “Step 2: Join the network from your applications”The other applications declare the network as external, so Compose uses the existing network rather than creating its own. Add it to every service that has to reach another deployment:
services: my_service: # ... networks: - acme-shared
networks: acme-shared: external: trueStep 3: Deploy the network first
Section titled “Step 3: Deploy the network first”Deploy all applications on the same deployment target, the network application before the others. For the first deployment, follow Create a Deployment. For the others, use + Deploy App on the deployment target card.
If you deploy another application first, it fails with network acme-shared declared as external, but could not be found. The controller retries every cycle, so the deployment starts by itself once the network exists.
Example: a backend and its database
Section titled “Example: a backend and its database”This example connects the backend of hello-distr, our example application, to a PostgreSQL database deployed separately.
Create a Docker application from each of the following Compose files and name them Network, Database and Backend.
The backend connects to the database as acme-db. Both read the password from a Distr secret, so it never appears in a deployment configuration.
services: network: image: 'registry.k8s.io/pause:3.10' restart: unless-stopped networks: - acme-shared
networks: acme-shared: name: acme-sharedservices: postgres: image: 'postgres:18.6-alpine3.24' restart: unless-stopped environment: POSTGRES_USER: acme POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: acme volumes: - 'postgres:/var/lib/postgresql/' networks: acme-shared: aliases: - acme-db healthcheck: test: pg_isready -h localhost -U acme -d acme start_interval: 1s interval: 5s retries: 6 start_period: 30s
volumes: postgres:
networks: acme-shared: external: truePOSTGRES_PASSWORD={{ .Secrets.POSTGRES_PASSWORD }}services: backend: image: 'ghcr.io/distr-sh/hello-distr/backend:0.4.25' restart: unless-stopped environment: DB_URL: postgresql+psycopg2://acme:${POSTGRES_PASSWORD}@acme-db/acme?sslmode=disable ports: - '80:5000' networks: acme-shared: aliases: - acme-backend healthcheck: test: [ 'CMD', 'python', '-c', "import urllib.request; urllib.request.urlopen('http://localhost:5000/health', timeout=1)", ] interval: 5s
networks: acme-shared: external: truePOSTGRES_PASSWORD={{ .Secrets.POSTGRES_PASSWORD }}Deploy the Network, then the Database and the Backend. The backend’s health check queries the database, so once the Database and Backend deployments are Healthy, the connection works. The Network deployment has no health check and stays Running. http://<host>/latest-message then answers with hello distr!.
Address other deployments by a network alias
Section titled “Address other deployments by a network alias”On the shared network, every container answers to its network aliases and to its service name. Service names tend to be generic, like postgres or backend. Two deployments can easily use the same one.
Docker then resolves the name to both containers in random order. Each request ends up at either of them.
- Give every service that other deployments connect to an alias under
networks.<name>.aliases(likeacme-db) and connect only through the alias. - If one application is deployed more than once on a deployment target, build the alias from a deployment variable, for example
acme-db-${INSTANCE}, so each deployment has its own. Do the same for published host ports, since only one deployment can bind the Backend’s port80, for example${HTTP_PORT}:5000.
Leave services that no other deployment needs off the shared network.
Keep the network definition stable
Section titled “Keep the network definition stable”When a new version of the network application changes the network, for example by adding a label, a driver option or a subnet, Compose tries to recreate it. Docker can’t remove a network that other deployments are still connected to, so the update fails with network acme-shared has active endpoints.
Settle the definition before the first deployment and keep it the same in every later version.
Related
Section titled “Related”- Docker Blue-Green Deployments: a setup of several connected deployments that shifts traffic between two versions of an application
- Docker Environment Variables: define the environment templates used for the password and the aliases
- Secrets Management: share credentials between deployments
- Docker Controller: how the controller runs every deployment as its own Compose project