Using Docker local networking
Both Docker and Docker Compose have command-line options to specify a Docker local network that the application will use. Using this Docker local network allows our containers to access another container's ports without having to bind/expose these ports to the host's ports.
Networking using .sh scripts
You use the docker network create command to create a named network that your containers can use to privately communicate with one another. You can have as many of these private networks defined as you like—you might want to work on multiple unrelated projects simultaneously and each needs its own network:
% docker network create chapter4
This command creates a network named chapter4 that we can use for our microservices example programs. We can destroy networks we have created using the docker network rm command:
% docker network rm chapter4
This command removes our chapter4 network from the system.
The start-mongodb.sh, start-redis.sh, start-mosca.sh, publisher/run.sh, and subscriber/run.sh scripts are used by the up.sh script to bring up our application's containers using the docker run command.
Let's examine our up.sh script:
#!/bin/sh
./stop-all.sh
We run the docker network create command to create our chapter4 network:
docker network create chapter4
We start our three servers:
./start-mosca.sh
./start-mongodb.sh
We also run ./start-redis.sh:
###### SUBSCRIBER
cd subscriber
./run.sh
Finally, we start the publisher:
###### PUBLISHER
# publisher needs to expose port 3000
# so we can access the WWW interface
cd ../publisher
./run.sh
The start-mongodb.sh and start-redis.sh scripts are roughly the same as the start-mosca.sh script. The relevant lines in the start-mosca.sh script are the ones for the docker run command:
docker run \
--name $SERVICE \
-d \
--restart always \
-e TITLE=$SERVICE \
--network chapter4 \
-v /tmp/mosca:/db \
matteocollina/mosca
Only the service name, which third-party/Docker Hub container to use, and any container to host directory bindings are specific to mongodb, mosca, or redis. They all share the chapter4 network.
The docker run command in the subscriber/run.sh script looks as follows:
docker run \
--name $SERVICE \
-d \
--restart always \
-e TITLE=$SERVICE \
--network chapter4 \
dockerfordevelopers/$SERVICE
We are no longer defining the HOSTIP environment variable because the Docker local networking system provides a DNS function that allows the programs in our containers to look up the other containers by name. The name is the name of the container, which is specified in the docker run commands scripts with the –name command-line option.
The relevant lines in subscriber/index.js are as follows:
const debug = require("debug")("subscriber"),
mongo_host = process.env.MONGO_HOST || "mongodb",
mongo_port = 27017,
mongoUrl = `mongodb://${mongo_host}:${mongo_port}`,
mqtt_host = process.env.MQTT_HOST || "mosca",
mqtt_port = 1883,
mqttUrl = `mqtt://${mqtt_host}`,
redis_host = process.env.REDIS_HOST || "redis",
redis_port = 6379,
redisUrl = `redis://${redis_host}`;
The code is designed to accept the MONGO_HOST environment variable; otherwise, it will use the mongodb container name. The same is the case for MQTT_HOST/mosca and REDIS_HOST/redis.
Note
We have been defining the HOSTIP, MONGO_HOST, MQTT_HOST, and REDIS_HOST environment variables, especially in the .sh script examples. Since we've been naming our containers using the --name switch on our docker run commands, Docker's local DNS will work with .sh scripts. That is, we don't need to define those environment variables if we name our containers. We still need to bind container ports to the host's ports, unless we also add the --network switch and docker network create to the Docker local network.
The down.sh script stops all the containers and removes the chapter4 network:
#!/bin/sh
docker stop publisher
docker stop subscriber
docker stop redis
docker stop mongodb
docker stop mosca
docker network rm chapter4
We can use these .sh scripts, but we've already learned that Docker Compose is the superior method for managing our microservices.
Networking with Docker Compose
The docker-compose.yml configuration file that we created is still enough to use as the base for using the docker-compose commands to manage our containers. However, we no longer need to expose or bind container ports to the host's ports; the only exception is we'll continue to bind port 3000 so that we can access the publisher web pages using our browser on the host. The base docker-compose.yml file does not bind port 3000, so we will continue to bind ports using the override file.
By default, if you specify no configuration files on the command line, docker-compose looks for docker-compose.yml and uses it, and then looks for docker-compose.override.yml and uses that.
If you need to specify a third configuration file, you must use the -f command-line switch for each configuration file.
Our docker-compose.override.yml file handles our production case:
version: '3'
services:
redis:
networks:
- chapter4
mongodb:
networks:
- chapter4
mosca:
networks:
- chapter4
publisher:
ports:
- 3000:3000
networks:
- chapter4
subscriber:
networks:
- chapter4
networks:
chapter4:
This file adds the chapter4 network, assigns it to each of the containers, and binds port 3000 in the publisher container to port 3000 on the host.
All we need to do to use docker-compose.yml and docker-compose.override.yml is run a simple docker-compose command:
% docker-compose up
After a few seconds, our five containers are up and running and we can access the application with our browser on the host. We can see it is all working. We can also do the following:
- Use the -d switch to run the containers in detached/daemon mode.
- Use docker-compose to stop and start any one or more containers.
- Use docker-compose to build any one or more containers.
- Use docker-compose logs to show the logs of any of our containers running in daemon mode.
What we now have is a pair of configuration files that work for production mode. We now need a way to work in development mode by binding our source code to the container's home directory.