Question Edited for simplicity and generalization as I've found the answer.
I'm trying to incorporate a Gluetun VPN container into my existing application that does a large array of fairly network heavy tasks. I'd like to connect a single container (a specific Queue worker for example) to use a VPN for only a single task which improves reliability drastically. I had much trouble figuring out the networking side of it and how to do this, as when you connect a container to Gluetun with network_mode: service:gluetun"
, It looses docker-compose's DNS functionality, and the ability to resolve the names of other services, giving an application error when connecting to, for example a Redis Container or Database container.
I wanted my existing networking to remain as it was, with only the specific containers using the VPN for external connections, while the other containers used the host server's network as they always have been. How to resolve this issue and setup in this manner?
There are 2 ways to solve this, But only one way solves it in the way I wanted.
To fully solve my problem, I ended up giving my dependent services a static IP, and using using the extra_hosts:
Docker-compose tag to add these services to the gluetun container's /etc/hosts file, which allows the gluetun container to resolve the service names, which the other containers use Docker's DNS. I also added the FIREWALL_OUTBOUND_SUBNETS
environment variable to the gluetun container with the same subnet as the network. I'm not 100% certain if this is required, But I did so based on the comment that helped me resolve the answer and it worked. Here's the docker-compose file :
version: '3'
services:
redis-service:
image: redis
ports:
- "6379:6379"
networks:
primary-network:
ipv4_address: 172.10.0.2 # Static IP address for service in subnet
default-queue-service:
image: queue
depends_on:
- redis-service
environment:
CONTAINER_ROLE: Default-Queue-worker
networks:
- "primary-network" # Uses primary network, External requests use host/server
vpn-queue-service:
image: queue
depends_on:
- redis-service
environment:
CONTAINER_ROLE: VPN-Queue-worker
network_mode: "service:gluetun" # Uses Gluetun's network, external requests use VPN
gluetun-service:
image: qmcgaw/gluetun
hostname: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
# volumes:
# - /yourpath:/gluetun
environment:
# See https://github.com/qdm12/gluetun-wiki/tree/main/setup#setup
- VPN_SERVICE_PROVIDER=<PROVIDER>
- VPN_TYPE=openvpn
# OpenVPN:
- OPENVPN_USER=<REDACTED>
- OPENVPN_PASSWORD=<REDACTED>
# Wireguard:
# - WIREGUARD_PRIVATE_KEY=<REDACTED>
# - WIREGUARD_ADDRESSES=<REDACTED>
# Timezone for accurate log times
- TZ=
# Server list updater
# See https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list
- UPDATER_PERIOD=
- SERVER_COUNTRIES=
- SERVER_REGIONS=
- FIREWALL_OUTBOUND_SUBNETS=172.10.0.0/16 # Required for accessing subnet ips (i think)
depends_on:
- redis-service
extra_hosts:
- "redis-service:172.10.0.2" # Adds redis-service now static ip to gluetun's /etc/hosts for name resolution instead of DNS
networks:
- "primary-network" # Gluetun needs to be on the same network as other services
networks:
primary-network:
ipam:
config:
- subnet: 172.10.0.0/16 # Defined static subnet ip. Make sure other docker networks do not conflict or it will error.
This was the standard answer I found most often while searching for this. This method consists of :
network_mode: "service:gluetun"
to ALL servicesBasically this treats all services as running on a single host (which is the gluetun container), so all services are on the same Localhost, and can be accessed as such by each service's respective port. This worked, But puts ALL containers external traffic through the VPN. Good if that's what you want, But not if you're trying to just have a single container route like I am. This is also more intrusive because it requires Application level environment variable changes for the host names. You don't need to define an explicit network in this case. The docker-compose file here is :
version: '3'
services:
redis-service:
image: redis
depends_on:
- gluetun
network_mode: "service:gluetun" # Uses Gluetun container's network
# NOTE ports cannot be defined here when using network_mode, Must define ports in the gluetun service instead.
default-queue-service:
image: queue
depends_on:
- redis-service
environment:
CONTAINER_ROLE: Default-Queue-worker
REDIS_HOST: localhost # This would be defined in your app env file
network_mode: "service:gluetun" # Uses Gluetun container's network, External requests use VPN
vpn-queue-service:
image: queue
depends_on:
- redis-service
environment:
CONTAINER_ROLE: VPN-Queue-worker
REDIS_HOST: localhost # This would be defined in your app env file
network_mode: "service:gluetun" # Uses Gluetun container's network, External requests use VPN
gluetun-service:
image: qmcgaw/gluetun
hostname: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks
- "6379:6379" # Redis , Redis Container uses Gluetun container's network so ports must be defined here, Cannot be defined in service.
# volumes:
# - /yourpath:/gluetun
environment:
# See https://github.com/qdm12/gluetun-wiki/tree/main/setup#setup
- VPN_SERVICE_PROVIDER=<PROVIDER>
- VPN_TYPE=openvpn
# OpenVPN:
- OPENVPN_USER=<REDACTED>
- OPENVPN_PASSWORD=<REDACTED>
# Wireguard:
# - WIREGUARD_PRIVATE_KEY=<REDACTED>
# - WIREGUARD_ADDRESSES=<REDACTED>
# Timezone for accurate log times
- TZ=
# Server list updater
# See https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-the-vpn-servers-list
- UPDATER_PERIOD=
- SERVER_COUNTRIES=
- SERVER_REGIONS=
Here, Both queue workers use the VPN network for external requests (All services network mode is defined as the gluetun service Including the dependent service Redis), so there is no difference between them besides application level. The services can access redis via the Localhost as they are all on the same network (all containers are using the same ip address), differentiating services by ports alone.