Docker networking: How to connect two containers.

We already learned how to create and run a single container. But nowadays most of the application uses multiple services. For example, to host a website we need a web server, a  programming language, and a database. So here we have to create more than one container. In this tutorial, we learn

  1. How to link/connect from one docker container to another ( Docker networking )

Before reading this tutorial I recommend you to go through the below links, it will help you to understand the basics of Docker container.

  1. Docker installation and configuration
  2. Create an image from the container

To learn about docker networking, I will use two containers. One container is for Apache and PHP and the other for MySQL. In the first container we will set up a WordPress hosting, so you know it should need to connect to MySQL.  let’s start with creating the first container.

Create the first container

Here, we use the official PHP docker image and will install WordPress in it. ( Or you can use official WordPress images )

[root@localhost ~]# docker pull php:7.0-apache
Trying to pull repository docker.io/library/php ...
7.0-apache: Pulling from docker.io/library/php

PHP with Apache image downloaded, now we can run a container from these images.

[root@localhost ~]# docker run -d --name Apache2php -p 80:80 php:7.0-apache
1508865d2728ea776653bed138702b4e79c17275874e7e0583d92c991aa37d17

Yes, our new Docker container  Apache2php is up and running.

Login to the container and install WordPress

[root@localhost ~]# docker exec -it Apache2php bash
root@1508865d2728:/var/www/html# ls
root@1508865d2728:/var/www/html# curl -O https://wordpress.org/latest.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 8537k 100 8537k 0 0 2581k 0 0:00:03 0:00:03 --:--:-- 2582k
root@1508865d2728:/var/www/html# tar -xzf latest.tar.gz
root@1508865d2728:/var/www/html# mv wordpress/* .

Now, we have a running container with Apache, PHP, and WordPress. But we need to make sure that one more thing. Here we are using MySQL as a DB engine, so PHP needs MySQL extension to connect to the MySQL.

Login to the docker and execute the PHP -i | grep mysqli it should show some result. If not we have to install it first.

root@e601d154010a:/var/www/html# php -i |grep mysqli
root@e601d154010a:/var/www/html#

In our case it doesn’t show any output, so we have to install it manually. For this I have followed the PHP official document, you can read the same here.

Execute below commands to install the MySQL extension.

root@e601d154010a:/var/www/html# docker-php-ext-configure mysqli
root@e601d154010a:/var/www/html# docker-php-ext-install mysqli
Build complete.

root@e601d154010a:/var/www/html# docker-php-ext-enable mysqli

warning: mysqli (mysqli.so) is already loaded!
root@e601d154010a:/var/www/html# php -i | grep mysqli
Additional .ini files parsed => /usr/local/etc/php/conf.d/docker-php-ext-mysqli.ini
mysqli
mysqli.allow_local_infile => On => On
mysqli.allow_persistent => On => On
mysqli.default_host => no value => no value
mysqli.default_port => 3306 => 3306
mysqli.default_pw => no value => no value
mysqli.default_socket => no value => no value
mysqli.default_user => no value => no value
mysqli.max_links => Unlimited => Unlimited
mysqli.max_persistent => Unlimited => Unlimited
mysqli.reconnect => Off => Off
mysqli.rollback_on_cached_plink => Off => Off
API Extensions => mysqli
root@e601d154010a:/var/www/html#

Yes., Now we have MySQL PHP extension enabled.

To Eliminate manual work like installing WordPress and PHP extension, we will create an image from this container. So next time we can pull this image from the repository and run it directly,  For this stop the running container,

# docker stop Apache2php

and execute below command

[root@localhost ~]# docker commit 1508865d2728 techiescorner/apache-wp
sha256:b43647f8fda80a89e447a76395e6e68ed203be13d7278286a28c9b5ff70f726e

[root@localhost ~]# docker images
REPOSITORY              TAG        IMAGE ID     CREATED         SIZE
techiescorner/apache-wp latest     b43647f8fda8 16 seconds ago  403 MB
docker.io/php           7.0-apache 647225efc6f2 4 days ago      367 MB

We have created a new image called “techiescorner/apache-wp”. To push this image to our repository for later use execute below command.

[root@localhost ~]# docker push techiescorner/apache-wp
The push refers to a repository [docker.io/techiescorner/apache-wp]
164265d99fe1: Pushed
44f45df05729: Mounted from techiescorner/apache2-php
75e13e83c45c: Mounted from techiescorner/apache2-php
94d1d153ee24: Mounted from techiescorner/apache2-php
9d9ce07adeea: Mounted from techiescorner/apache2-php
latest: digest: sha256:b6bda42b08bc3bfcfb68603284752eabad32230a0119ed00e9a9ffe5737d4931 size: 3455

Here, we have created our Docker image and pushed it to our docker hub repository.

To know more about how to create an image from the running container, please click here

Now run a new container from these images ( techiescorner/apache-wp  image)

[root@localhost ~]# docker run -d --name ApacheWP -it -p 80:80 techiescorner/apache-wp
3b4dfd238776173f2bb4c029b23d720565106b5ff56a170acb7e241f9a7c7702

[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE                     COMMAND                  CREATED             STATUS              PORTS                NAMES
3b4dfd238776   techiescorner/apache-wp   "docker-php-entryp..."   51 seconds ago      Up 51 seconds       0.0.0.0:80->80/tcp   ApacheWP

Yes, our web server ( container name: ApacheWP ) is running. Move to your browser and access the IP address to see our website is loading with the WordPress setup page.

To complete the WordPress installation we need a Database server, for this, we will create another container.

Create a second container:

For this, I am using an official MySQL ( version 5.6) container image provided by Oracle from the docker HUB.

Download the image.

[root@localhost ~]# docker pull mysql:5.6
Trying to pull repository docker.io/library/mysql ...
5.6: Pulling from docker.io/library/mysql
683abbb4ea60: Pull complete
0550d17aeefa: Pull complete
7e26605ddd77: Pull complete
Digest: sha256:0267b9b43034ed630e94f846ca825140994166c6c7d39d43d4dbe8d1404e1129
Status: Downloaded newer image for docker.io/mysql:5.6

[root@localhost ~]# docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             SIZE
docker.io/mysql                     5.6                 7edb93321b06        5 days ago          256 MB
docker.io/techiescorner/apache-wp   latest              ee7dbf0c65da        6 days ago          431 MB
docker.io/php                       7.0-apache          647225efc6f2        2 weeks ago         367 MB

Create a container from this MySQL image. This container will use as our Database server.

# docker run --name dbserver -e MYSQL_ROOT_PASSWORD=rootpw -d mysql:5.6
083047bf94bf3c62a831f02088dd7770923c017005517841db516b2d082d9537

Don’t forget to assign a root password for the MySQL server.

Now we have two running containers.

But to work the  WordPress website hosted in the apacheWP container, it should connect to the database server. How can we establish this? for this, docker service is providing an inbuilt network. To list the available network run the following command.

# docker network ls

The Bridge network is the default network where all the containers will run. Let’s inspect our docker containers network. For this run the following command.

[root@localhost ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "cc3c870c95d7090a074b39b7db3dbecae3273bccff09c0f98f649fb3e68e9cfe",
        "Created": "2018-08-05T11:00:40.878317292-04:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "3394470530fd2e67bda175aef0f2fb263d4bb866460ebf16183f738103ef8516": {
                "Name": "dbserver",
                "EndpointID": "e473ec6f8e848744a6969724d18d7f6544fd17b4460758bbe244ad5b7d032a0d",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "3b4dfd238776173f2bb4c029b23d720565106b5ff56a170acb7e241f9a7c7702": {
                "Name": "ApacheWP",
                "EndpointID": "8f671c1850eb3d6e7814d5f775bfe37a414bcfbcd233cc868bdd1e90e9f278d4",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

In the above command output, we can see our containers ( apacheWP and DB server ) listed with an IP address. Now each docker has an IP address, next we need to make sure that each container can talk to each other. Let’s log in to the apacheWP container and initiate a connection to the DB server ( 172.17.0.3). Telnet command may not be present, but you can use the curl command to check this.

[root@localhost ~]# docker exec -it ApacheWP bash

root@4eb5b4e2304d:/var/www/html# curl 172.17.0.3:3306
5.6.40zqFJ!bOB▒=I7vnFQC?ON{mysql_native_password!▒▒#08S01Got packets out of order

Yes, we can successfully connect to the DB server.

Now we could connect two containers but there are still a few issues.

  1.  We need to manually add an entry in the /etc/hosts file so apache PHP container knows that “dbserver” is resolving to 172.17.0.3 IP address. This is not easy because each time the IP address of the containers may change.
  2.  The default bridge network is shared by every container, so this is not a secure way to connect containers.

To overcome these issues docker providing an option to create our network. It also helps to resolve manually adding /etc/hosts file issue, let’s see how it work.

Create our first network named mynetwork.

[root@localhost ~]# docker network create mynetwork
86226dafab5a72f1e1386a5edc49184d29cc92d79c16e8fa029bcf31e83268b1

[root@localhost ~]# docker network ls
NETWORK ID      NAME         DRIVER SCOPE
130ff0138ed2    bridge       bridge local
e8d44c5e9f03    host         host   local
b90e5d4ec793    mynetwork    bridge local
917846604c29    none         null   local

We have created our network with the help of the “docker network create” command. Now we have to run our container on this network. For this, stop or delete existing containers and run new ones.

  1. Run ApacheWP  container on mynetwork

I have used the same command that we executed earlier to bring up a container. The “–net” flag is used to add our network.

[root@localhost ~]# docker run -d --name ApacheWP --net mynetwork -p 80:80 techiescorner/apache-wp
85c7b707768c136898bd60654a956f5ce61c3e2f7400fb68217dbf19a7b2a013

Let’s do a network inspection again.

[root@localhost ~]# docker inspect mynetwork
[
    {
        "Name": "mynetwork",
        "Id": "86226dafab5a72f1e1386a5edc49184d29cc92d79c16e8fa029bcf31e83268b1",
        "Created": "2018-08-05T14:57:03.817326034-04:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "85c7b707768c136898bd60654a956f5ce61c3e2f7400fb68217dbf19a7b2a013": {
                "Name": "ApacheWP",
                "EndpointID": "8d0fe026c980bec8d7a4202705a50ce2f2b2745a7b005154f9f7f926f4a1882b",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

Login to our ApacheWP container and see the changes that happened.

Open /etc/hosts file and you can see that docker has automatically added a new host entry. Just make sure that the host is correctly resolving the ApacheWP container.

root@85c7b707768c:/var/www/html# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.2      85c7b707768c
root@85c7b707768c:/var/www/html# curl -I 85c7b707768c:80
HTTP/1.1 302 Found
Date: Sun, 05 Aug 2018 19:00:49 GMT
Server: Apache/2.4.25 (Debian)
X-Powered-By: PHP/7.0.31
Location: http://85c7b707768c/wp-admin/setup-config.php
Content-Type: text/html; charset=UTF-8

root@85c7b707768c:/var/www/html#
root@85c7b707768c:/var/www/html# curl -I ApacheWP:80
HTTP/1.1 302 Found
Date: Sun, 05 Aug 2018 19:01:31 GMT
Server: Apache/2.4.25 (Debian)
X-Powered-By: PHP/7.0.31
Location: http://ApacheWP/wp-admin/setup-config.php
Content-Type: text/html; charset=UTF-8

root@85c7b707768c:/var/www/html#

From the above two curl command output, we can confirm that the container ID and Container name (ApacheWP) is resolving to the correct IP address and showing our website ( redirecting to WordPress configuration page. http://ApacheWP/wp-admin/setup-config.php )

Next, we will launch our database server in the same network. So both containers can communicate with each other.

[root@localhost ~]# docker run --name dbserver --net mynetwork -e MYSQL_ROOT_PASSWORD=rootpw -d mysql:5.6
67f005807947fa54c79cfa585b1f31515ffd3873d3cf4203a2db4228866b2d31

Now login to the ApacheWP container and make sure that it can connect to our data server

[root@localhost ~]# docker exec -it ApacheWP bash
root@85c7b707768c:/var/www/html#

root@85c7b707768c:/var/www/html# curl dbserver:3306
5.6.41>edHyLLv▒37X6D5{0z6<lmysql_native_password!▒▒#08S01Got packets out of order

Yes, from the webserver container we can connect to the DB server. Now go to the browser and try to access the IP address.

It will show the WordPress installation page. To complete this we need the following details.

Database name, hostname, DB user, and password. So let’s log in to our data server and create these details or we can pass these values at the time of docker running.  here, I am passing all the values at the time of docker creation. For this execute below commands.

[[root@localhost ~]# docker stop dbserver
dbserver
[root@localhost ~]# docker rm dbserver
dbserver
[root@localhost ~]#  docker run --name dbserver --net mynetwork -e MYSQL_ROOT_PASSWORD=rootpw -e MYSQL_DATABASE=wpdb -e MYSQL_USER=wpuser -e MYSQL_PASSWORD=wppasswd -d mysql:5.6
d887a2962626fd31451402d3efba6b28917c759cd564ed2df381b00d56212101

[root@localhost ~]# docker ps -a
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                NAMES
d887a2962626        mysql:5.6                 "docker-entrypoint..."   22 seconds ago      Up 22 seconds       3306/tcp             dbserver
85c7b707768c        techiescorner/apache-wp   "docker-php-entryp..."   13 minutes ago      Up 13 minutes       0.0.0.0:80->80/tcp   ApacheWP

Go back to the browser and paste these details in the mentioned columns.

You can see here I have used “dbserver” has the hostname.  Once you added all details click on the submit button.

Yes, our WordPress site is now live!!..

Here we have executed only a few commands to set up our website in the docker container. Let’s collect these command and add to a bash script file.

cat setup.sh

[root@localhost ~]# cat setup.sh
#!/bin/bash

#create network mynetwork
docker network create mynetwork

#Build first container (ApacheWP)
docker run -d --name ApacheWP --net mynetwork -p 80:80 techiescorner/apache-wp

#Build database server
docker run --name dbserver --net mynetwork -e MYSQL_ROOT_PASSWORD=rootpw -e MYSQL_DATABASE=wpdb -e MYSQL_USER=wpuser -e MYSQL_PASSWORD=wppasswd -d mysql:5.6
[root@localhost ~]#

Now it is very easy to share this App with a friend or you wish to install it in a server that has docker installed. Just executing this script will help you to set up the entire WordPress website.

3 comments

  1. Olivia Reply

    Hi! Thank you for your posting.
    I built zen-cart in docker server with mysql using your method.
    However I can’t see the database of zen-cart.
    If I login to dbserver container and insert “mysql -u root -p”, “ERROR 1045 (28000): Access denied for user ‘root’@’localhost’ (using password: NO)” is shown.
    How can I see the database??

    Also, I have one more question.
    Firstly, I tried to build docker-compose to connect mysql and zen-cart.
    But according to your post, your method also make connection.
    So, It means that I don’t need to build docker-compose file right?

    I’m sorry to my english speaking skill. Thank you so much!

  2. admin Post authorReply

    Hi Olivia,

    Remove the existing database container and create a new one with below command.

    docker run –name dbserver –net mynetwork -e MYSQL_ROOT_PASSWORD=rootpw -e MYSQL_DATABASE=wpdb -e MYSQL_USER=wpuser -e MYSQL_PASSWORD=wppasswd -d mysql:5.6
    [ Change docker name, network name, database name and user accordingly ]

    This command will create a MySQL database docker container with following details.
    DB name : wpdb
    DB username : wpuser
    DB password: wppasswd
    You can use these details in your Zencat configuration file.
    Also, if you want to connect databse from DB server you have to run below command
    root@localhost ~]# docker exec -it dbserver bash
    root@d887a2962626:/# mysql -u wpuser -pwppasswd

  3. Tripp Reply

    Thanks for this overview. This was amazingly helpful for a dabbler like me trying to learn Docker and also learning it without using the Link commands.

Leave a Reply

Your email address will not be published. Required fields are marked *