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
- 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.
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.
- 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.
- 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.
- 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.
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!
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
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.