Ruddra.com

Basic Networking in Docker

Basic Networking in Docker
Photo by Taylor Vick on Unsplash

We already know that Docker is used for containerization. But networking in docker makes it even better tool for deployment. You can make standalone deployments in containers and communicate between them, or make containers act as host, or even assign mac addresses to containers and act them as devices. It does not matter which host machine you are in, you can make dockers communicate in-between them. In this article, we are going to discuss about bridge networking in docker, and in the end will see on how to communicate from container to host or vice versa.

Communication between containers

If you have several standalone applications in different containers and need to communicate between them, then you can use bridge as network driver in docker. Its the default driver, it will be assigned if you don’t specify network driver type. It is used when you deploy standalone applications in different containers and they need communication.

How it works

The docker documentation states:

In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network.

Means, the containers connected to bridge network can communicate with each other, but can’t communicate which are outside of that network. It won’t be exposed unless you explicitly do that.

Create bridge network

You can create a bridge network by:

docker network create skynet

Or remove it:

docker network rm skynet

You can also inspect the network using:

docker network inspect skynet

Connect containers to network

After creating the network, now its time to add your containers to that network like this:

 docker create --name nz01 \
  --network skynet \
  --publish 8080:80 \
  nginx:latest

Or you can add a running container to network:

docker network connect skynet nz01

Disconnect containers from network

You can use the following command to do that:

docker network disconnect skynet nz01

Examples on how to communicate between containers

It is pretty simple, you need to use the name of a container and port it is exposing. For example, if you want to access nginx container(named nz01 in previous example) from another container, then try like this:

wget nz01:80

Keep in mind that the port number is the port where the application is running inside the container, not the port it has exposed. In docker, port mappings are writtern in <EXPOSED PORT>:<INTERNAL PORT>, in this example 8080 is accessable from outside world, where nginx is running in port 80 inside the container.

Here is another example, lets say an web application is running in container web at port 8000 and from nginx you want to expose it. Then the nginx configuration should look like this:

upstream web {
  ip_hash;
  server web:8000; // here web is the name of the container or service if you are using docker compose and application is running at port 8000
}

server {

    location / {
        proxy_pass http://web/;
    }
    listen 8000;
    server_name localhost;
}

Example with ‘Docker Compose’

Docker Compose provides a better way of writing networks. Here is an example:

version: "3"
services:
  nginx:
    image: nginx:alpine
    container_name: nz01
    ports:
      - "8000:8000"
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
    depends_on:
      - web
    networks:
      - skynet
  web:
    build:
      context: .
      dockerfile: compose/django/Dockerfile
    container_name: dz01
    volumes:
      - ./src:/src
    expose:
      - "8000"
    networks:
      - skynet

networks:
  skynet:
    driver: bridge

Here I just provided a networks section in each of the services defining which network to connect. And inside networks section at the bottom, I have defined which driver to use for communication. We could have defined multiple networks if needed.

Communication between host and container

From container to host

Communication from container to host is pretty straight forward. You just need to expose the container in certain port and from host machine access it through localhost:port or 127.0.0.1:8000. For example:

> docker run -p 8000:80 -it web
> wget localhost:8000

From host to container

This communication has been made simple for MacOs and Windows, but not in linux(at the moment of writing). All you need to do is use host.docker.internal. For example, if you want to use postgres database in django from host machine:


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'host.docker.internal',
        'PORT': 5432,
    }
}

But for linux machine, you can add the following lines in docker-entrypoint.sh(copy pasted from this article):

HOST_DOMAIN="host.docker.internal"
ping -q -c1 $HOST_DOMAIN > /dev/null 2>&1
if [ $? -ne 0 ]; then
  HOST_IP=$(ip route | awk 'NR==1 {print $3}')
  echo -e "$HOST_IP\t$HOST_DOMAIN" >> /etc/hosts
fi

(main entrypoint)

What its doing is that if host.docker.internal does not work when pining, it will add the host.docker.internal as alias of HOST IP and add it in /etc/hosts.

In conclusion

Although in this article we focused on bridge networking, but there or other types of networking which can be used based on situations. Networking in docker is a breeze compared to doing it manually, and making it a very powerful means of deployment and distribution(along with its awesome platform agnostic services). Thank you for reading, if you have any opinion regarding this article, please share in the comment section below.

Last updated: Mar 18, 2024


← Previous
Implement Newsletter Subscription Using Staticman

Use staticman to build newsletter services, no need to use third party websites.

Next →
Use Docker for Accessing Database in AWS CodeBuild

Using docker to access temporary database in AWS CodeBuild when running test cases.

Share Your Thoughts
M↓ Markdown