Docker ( Dockerfile and communication between containers )

02 / May / 2015 by Navjot Singh 0 comments

In this blog, we would be using Dockerfile to create images and see how two docker containers would communicate using below scenario.

Scenario

Create two docker images using Dockerfile, one would host wordpress website and other would hold the website’s database. Using these images, create two containers, one for database hosting and other for website hosting.

Although we can create Dockerfile at any location, yet we will be following a directory structure as follows:

[js]mkdir ~/docker/{web,database}[/js]

Creation of mysql image

We will start first by creating Dockerfile for mysql image for database (say mysql image).We will use location ~/docker/database for mysql image creation.

[js]cd ~/docker/database
vi Dockerfile[/js]

We will go through each line we add into Dockerfile and understand it step-by-step.

1. Selection of Base Image: First, we need to first specify the base image on which we will setup our mysql. Using FROM instruction, we specify the base image with version as below. We can define here our own custom image.

[js]FROM ubuntu:15.04[/js]

2. Defining Maintainer: The author of the image can be defined using MAINTAINER instruction which sets the author field of the image.

[js]MAINTAINER Navjot Singh <navjots[at]intelligrape[DOT]com>[/js]

3. Installing mysql: Now, we can install any package on the base image using RUN command. We will install mysql after performing repository update.

[js]RUN apt-get update
RUN apt-get -y install mysql-server mysql-client[/js]

4. Changing bind-address: To change the bind -address, we need to edit /etc/mysql/mysql.conf.d/mysqld.cnf file. This allows mysql to listen to any request coming from other servers.

[js]RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/mysql.conf.d/mysqld.cnf[/js]

5. Adding root user and setting password: We need to add a user which can access database from the web container which we will be creating later. To accomplish this we need mysql service to be running. In Dockerfile, each line creates a different commits on the file-system and memory state is not retained in commits but only file-system state. So we accomplish this operation by using shell script and we will call this shell script from Dockerfile. The shell script (say start.sh) should be present at the same path where Dockerfile is present. The content of the script would be:

[js]cat start.sh
#!/bin/bash
if ! -f /var/lib/mysql/ibdata1
then
mysql_install_db
/usr/bin/mysqld_safe &
sleep 5
mysqladmin -u root -h localhost password shroot12
mysql -uroot -pshroot12 mysql -e " GRANT ALL ON *.* TO root@’%’ IDENTIFIED BY ‘shroot12’ WITH GRANT OPTION; FLUSH PRIVILEGES"
killall mysqld && sleep 5
fi
/usr/bin/mysqld_safe[/js]

This script checks if the database has been initialized every-time when container is created. If the database is not initialized, it initializes the database and start the mysql service. Now we can assign password to root user and allow root user to access the service from servers other than localhost.

Add the shell script into Dockerfile and make it executable:

[js]ADD ./startup.sh /opt/startup.sh
RUN chmod +x /opt/startup.sh[/js]

6. Expose port 3306: To allow 3306 port of database container to accept connection from outside world, we expose this port.

[js]EXPOSE 3306 [/js]

7. Creating database image: We have completed our Dockerfile. The location should have “Dockerfile” and “start.sh” script.
Consolidated Dockerfile is as below.

[js]cat Dockerfile
FROM ubuntu:15.04
MAINTAINER Navjot Singh <navjots[at]intelligrape[DOT]com>

RUN apt-get update

RUN apt-get -y install mysql-client mysql-server
RUN sed -i -e"s/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/mysql.conf.d/mysqld.cnf

ADD ./startup.sh /opt/startup.sh
RUN chmod +x /opt/startup.sh
EXPOSE 3306

CMD ["/bin/bash", "/opt/startup.sh"][/js]

We can create mysql image using following command.

[js]docker build -t mysql . [/js]

The above command searches “Dockerfile” in the current directory and creates image named “mysql”.
We can see this image using “docker images” command.

8. Using host’s directory for database: If we are storing some data into the database of this container, this data would get deleted once we stop the container.In order to save this data even when the container does not exits anymore, we have to map one directory present on host ( say /var/lib/mysql-container) to the directory present inside the container. We can do this while creating container with -v option as follows.

Running container using mysql image:

[js]docker run -d -v /var/lib/mysql-container:/var/lib/mysql -n database -p 3306:3306 mysql [/js]

-d : run container as daemon
-n “ database” : set name of the container
-p 3306:3306 : map container’s 3306 port to host’s 3306 port
-v /var/lib/mysql-container:/var/lib/mysql : maps host’s directory /var/lib/mysql-container to container’s directory “/var/lib/mysql”

Creation of web-server image

Now we will start creating web-server image.
We will use location ~/docker/web for web-server image creation.

[js]cd ~/docker/database
vi Dockerfile[/js]

We will go through each line we add into Dockerfile and understand it step-by-step.

1. Selection of Base Image: First, we need to first specify the base image on which we will setup our web server. Using FROM instruction, we specify the base image with version as below. We could define here our own custom image.

[js]FROM ubuntu:15.04[/js]

2. Defining Maintainer: The author of the image can be defined using MAINTAINER instruction which would set in the author field of the image.

[js]MAINTAINER Navjot Singh <navjots[at]intelligrape[DOT]com>[/js]

3. Installing Web Server and dependencies: Now, we can install any package on the base image using RUN command. For our scenario, we will download latest wordpress zip package and use it to create web-server. We will install nginx, php, zip/unzip and wget to do this task after performing repository update.

[js]RUN apt-get update
RUN apt-get install -y php5-common php5-cli php5-fpm php5-mysql
RUN apt-get install -y wget zip unzip[/js]

4. Downloading and Configuring WordPress: We will now download wordpress and unzip it. Then we will configure database details inside it.
Download:

[js]RUN wget https://wordpress.org/latest.zip [/js]

Unzip:

[js]RUN unzip latest.zip [/js]

Creating wp-config.php:

[js]RUN cp wordpress/wp-config-sample.php wordpress/wp-config.php [/js]

Update database details:

[js]RUN sed -i "s/database_name_here/test/g" wordpress/wp-config.php
RUN sed -i "s/username_here/root/g" wordpress/wp-config.php
RUN sed -i "s/password_here/shroot12/g" wordpress/wp-config.php
RUN sed -i "s/localhost/db/g" wordpress/wp-config.php[/js]

5. Run nginx service in foreground: To use docker container as a daemon, we need to have one service running in the foreground inside the container otherwise the container would exit at the time we start it. We will configure nginx to run in the foreground by adding “daemon off” in nginx.conf file.

[js]RUN echo ‘daemon off;’ >> /etc/nginx/nginx.conf[/js]

6. Adding default virtual host from host machine: We can either use the default installation file or add the default file from host machine. We will add default file from host machine. We need to have php enabled in this file and location of this file should be same as the location of the Dockerfile we are creating.

[js]ADD default /etc/nginx/sites-available/default[/js]

7. Exposing port 80: Since the web server will run on port 80 of the container. We make this port available using EXPOSE command. This command tells docker about the container ports configured for listening the host.

[js]EXPOSE 80[/js]

8. Running multiple services: We need ngnix and php5-fpm services running in a single container. CMD command is used to pass command to the container. Since we will be starting two services, we need to run CMD twice. But in Dockerfile, each line creates a different commits on the file-system. So memory state is not retained in commits but only file-system state. To enable multiple service we will use shell script(say start.sh) and then add the script in the Dockerfile. It’s path is same as the Dockerfile’s path.The content of this script would be:

[js]#!/bin/bash
service php5-fpm start
service nginx start[/js]

Add shell script and make it executable :

[js]ADD start.sh /opt/start.sh
RUN chmod +x /opt/start.sh[/js]

9. Running Script: We need to run the above added script which can be done using CMD command.

[js]CMD ["/bin/bash", "/start.sh"][/js]

We have completed our “Dockerfile” to create image of web-server.

10. Creating web image: We have completed our web Dockerfile. The location should have “Dockerfile”, “default” and “start.sh” script.
Consolidated Dockerfile is as below.

[js]cat Dockerfile
FROM ubuntu:15.04
MAINTAINER Navjot Singh <navjots@intelligrape.com>
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y php5-common php5-cli php5-fpm php5-mysql
RUN apt-get install -y wget mysql-client zip unzip
RUN echo ‘daemon off;’ >> /etc/nginx/nginx.conf
RUN wget https://wordpress.org/latest.zip
RUN unzip latest.zip
RUN cp wordpress/wp-config-sample.php wordpress/wp-config.php
RUN sed -i "s/database_name_here/test/g" wordpress/wp-config.php
RUN sed -i "s/username_here/root/g" wordpress/wp-config.php
RUN sed -i "s/password_here/shroot12/g" wordpress/wp-config.php
RUN sed -i "s/localhost/mysql/g" wordpress/wp-config.php
ADD default /etc/nginx/sites-available/default
ADD phpinfo.php /wordpress/
ADD start.sh /start.sh
RUN chmod +x /start.sh

EXPOSE 80
CMD ["/bin/bash", "/start.sh"][/js]

Content of “default” file

[js]cat default
server {
listen 80 default_server;
listen [::]:80 default_server;
root /wordpress;
index index.html index.php index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
} [/js]

We can create web image using following command.

[js]docker build -t web . [/js]

The above command searches “Dockerfile” in the current directory and creates image named “web”. We can see this image using “docker images” command.

10. Link web container with the database container: We have created image named web. Using this image we will create container named “wordpress” which will link to the database container. This container will also maps it’s 80 port to the 80 port of host server.
Running container using web image:

[js]docker run -d -n wordpress -p 80:80 –link database:database web [/js]

-d : run container as daemon
-n wordpress : create container with name “wordpress”
-p 80:80 : maps 80 port of host to 80 port of container
–link db:database : enables wordpress container to communicate with database container and creates alias “db” to database. We have used this alias in the wp-config.php to specify database host.

Now , we have wordpress container communicating with database container.
We can now test it by browsing the website using public ip of host system in web-browser.

FOUND THIS USEFUL? SHARE IT

Leave a Reply

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