Docker for Developers
上QQ阅读APP看书,第一时间看更新

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.