DevOps

Docker: Custom networks

Profil Picture

Guillaume Briday

3 minutes

This article is a follow-up to the presentation I gave on Docker: Understanding and Implementing Docker. I received some relevant feedback and wanted to revisit points that I believe are important.

Networks

I didn't specify this earlier, but Docker has a default network. It's called bridge, and if you don't change the configuration, all containers will be associated with this network. What does this mean for us? If you don't need to isolate your containers, they will all be able to communicate with each other on this network without requiring links, for instance. To achieve this, you can use either the container's IP address or the name assigned to a container via the --name option.

You can list your networks using the following command:

$ docker network ls

Dependencies between containers

Links are not only used for this purpose. Beyond creating private networks between containers to transmit sensitive information, they allow you to define a launch order and dependencies between your containers. Additionally, they enable you to create aliases for your container names.

For example, if your container is named mysql, but another service needs it to be called database, you can create an alias with the syntax --link mysql:database. If the second argument is the same as the first, it becomes optional. Thus, in your database configuration, you can directly set the host as database instead of using the container's IP address or mysql.

For dependencies, if you're using docker-compose up -d, the question doesn’t arise because all containers are launched without conditions.

However, if you need to launch a container that depends on another (for example, a PHP container that runs tests and requires a MySQL container), with the docker-compose run or docker-compose exec commands, Docker won't know that the PHP container depends on the MySQL container to function. It will only launch the container you requested, causing your tests to fail.

Links ensure that dependent containers are also launched.

If no links are used, no other containers are launched. However, docker-compose creates a custom network to avoid using the default one, maintaining isolation between your projects.

$ docker-compose run --rm blog-server ./vendor/bin/phpunit
Creating network "laravelblog_default" with the default driver
PHPUnit 6.4.4 by Sebastian Bergmann and contributors.
...

If links are used, all dependent containers are also launched:

$ docker-compose run --rm blog-server ./vendor/bin/phpunit
Creating laravelblog_redis_1 ...
Starting laravelblog_mysql_1 ...
Starting laravelblog_mysql-test_1 ... done
Creating laravelblog_redis_1 ... done
PHPUnit 6.4.4 by Sebastian Bergmann and contributors.
...

Since custom networks became available, it's no longer recommended to use links, which have been deprecated. If you need to isolate containers, it's better to use a dedicated custom network and manage dependencies with depends_on.

A simplified version of our old docker-compose.yml would look like this:

services:
  blog-server:
-    links:
+    depends_on:
      - mysql
      - mysql-test
      - redis

Custom Networks

As we've seen, you can define custom networks. These need to be specified in two places: at the same level as services to create them (called top-level networks) and within the services themselves to use them (service-level networks). Even though the networks section is defined after the services section in your docker-compose.yml, they are created first.

To define a network with docker-compose:

services:
  blog-server:
    depends_on:
      - mysql

networks:
  backend:
    driver: bridge

In this example, we’ve created a network named backend with the bridge driver, which is the default driver in Docker. You can find all available options in the official documentation. I won’t go over all of them, as it’s more important to understand how it works; the rest depends on your needs.

A service can join one or more networks:

services:
  blog-server:
    depends_on:
      - mysql
    networks:
      - backend
      - frontend

networks:
  backend:
    driver: bridge
  frontend:
    driver: bridge

The names of networks created with docker-compose will follow the pattern [projectname]_[networkname]. In our case, it would be laravelblog_backend. You can inspect a container with the command:

$ docker inspect <container_id>

You can also create networks with Docker:

$ docker network create --driver bridge <network_name>

And to join a network when launching a container:

$ docker run --name blog-server -v $(pwd):/application --network <network_name> -d laravel-blog

In the network section, you’ll notice two networks, each with distinct IPs for the same container depending on the network.

If you don’t need to create a custom network for specific cases, it's recommended to use the default network, as docker-compose handles it for you.

I've updated my docker-compose.yml for the laravel-blog project if you’d like to see the complete example.

Thank you!

Simplify your time tracking with Timecop

Timecop is a time tracking app that brings simplicity in your day to day life.

Timecop projects