When working with Docker Swarm multi-stack deployments, developers often need to establish communication between services in different stacks. While the obvious solution is exposing ports, this approach introduces unnecessary security risks and complicates network architecture.
Docker Swarm provides a built-in DNS server (127.0.0.11) that automatically resolves service names within the same stack. For cross-stack communication, the naming convention follows this pattern:
service_name.stack_name
The documentation you referenced applies specifically to Docker Cloud (now deprecated), not current Docker Swarm implementations. In modern Docker Swarm:
- Cross-stack DNS only works when using overlay networks attached to both stacks
- The stacks must share at least one common overlay network
- Services must be connected to this shared network
Here's how to properly configure your stacks:
# First, create an overlay network accessible to both stacks
docker network create --driver overlay --attachable shared_net
# Deploy your stacks with network configuration
# main-stack.yml
version: "3.8"
services:
my_app:
image: my_app_image
networks:
- shared_net
networks:
shared_net:
external: true
# mon-stack.yml
version: "3.8"
services:
grafana:
image: grafana/grafana
networks:
- shared_net
networks:
shared_net:
external: true
After deployment, you can verify connectivity from within a container in the main stack:
# Access a container in the main stack
docker exec -it main_stack_container sh
# Test DNS resolution
nslookup grafana.mon
# Should return the proper IP
# Test connectivity
curl http://grafana.mon:3000
If you can't use shared networks, consider:
- Ambassador Pattern: Create a proxy service in the target stack
- API Gateway: Implement a centralized access point
- Service Mesh: Use tools like Linkerd or Istio
If DNS resolution still fails:
- Verify both services are running:
docker service ls
- Check network attachments:
docker network inspect shared_net
- Test basic connectivity between containers
- Inspect DNS configuration:
cat /etc/resolv.conf
inside containers
When working with multi-stack deployments in Docker Swarm, accessing services across stack boundaries presents unique challenges. The traditional approach of exposing ports creates security vulnerabilities and complicates network architecture. Let me share a practical solution I've implemented in production environments.
The 127.0.0.11 DNS resolver is Docker's magic sauce for service discovery. However, its cross-stack capabilities aren't immediately obvious. Here's what actually works:
# This won't work cross-stack:
ping grafana.mon
# The proper FQDN format for cross-stack access:
ping tasks.grafana_mon
For cross-stack communication to function, both stacks must share the same overlay network. Here's how to set it up:
# Create the shared network (run once)
docker network create --driver overlay --attachable shared_net
# In your compose files:
services:
grafana:
networks:
- shared_net
networks:
shared_net:
external: true
Let's examine a complete solution for accessing Grafana from another stack:
# main-stack.yml
version: "3.8"
services:
exporter:
image: prom/node-exporter
networks:
- shared_net
networks:
shared_net:
external: true
# mon-stack.yml
version: "3.8"
services:
grafana:
image: grafana/grafana
networks:
- shared_net
networks:
shared_net:
external: true
To confirm everything works as expected:
# From a container in main stack:
docker exec -it main_exporter_1 ping tasks.grafana_mon
# Expected output:
PING tasks.grafana_mon (10.0.1.23): 56 data bytes
64 bytes from 10.0.1.23: seq=0 ttl=64 time=0.123 ms
For production environments, consider these enhancements:
- Implement network policies for security
- Use Docker secrets for authentication
- Configure health checks for reliability
The key takeaway is that tasks.serviceName_stackName
is the reliable pattern for cross-stack discovery when using shared overlay networks. This approach maintains security while providing the connectivity needed for microservices architectures.