Skip to content

Jesses Software Engineering Blog

Jun 09

Jesse

Docker LAMP Stack

Docker is a tool used for shipping, or deploying, web applications along with their environment. Using Docker allows for easy sharing and recreating of application environments. This is extremely useful for developers as the stack and application can be built as a compilation of containers and easily deployed or modified.

In this tutorial I will create a Docker LAMP environment using two containers: one for Apache and one for MySQL.

Installation

To install Docker on Ubuntu 14.04, or see other installation instructions

wget -qO- https://get.docker.com/ | sh
docker --version

Docker is treated like other services

sudo service docker status
sudo service docker start

To test installation

sudo docker run ubuntu:14.04 /bin/echo 'Hello world'

Docker Overview

Docker uses containers which are built on top of Docker images to run applications and services. Typically there will be one service per container i.e. a separate container for Apache and MySQL. Images can be minimal i.e. an OS like Ubuntu 14.04, or complex and built using a Dockerfile. Once an image has been created a container can be ran on top of that image.

Some common Docker commands

# show available images
sudo docker images

# show running containers, or all containers
sudo docker ps
sudo docker ps -a

# to stop / start a container
sudo docker stop <name | id>
sudo docker start <name | id>

# to see info about a container, or specific info
sudo docker inspect <name | id>
sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' <name | id>

# to delete a container
sudo docker rm <name | id>

# to delete all containers
sudo docker rm -f $(sudo docker ps -a -q)

# to delete an image
sudo docker rmi <name | id>

Docker LAMP Containers

When building containers it’s important to note that Docker containers will close when there is no active process running in the container. Therefore when making containers for a service it is import to run that service in the foreground ensuring that the Docker container will continue to run.

For the MySQL container it is easier to use an existing Docker image via Docker Hub, a public repository for Docker images.

# pull the docker image
sudo docker pull mysql

# run the container on top of the image
sudo docker run -p 3900:3306 --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:latest

# test connection (if running MySQL locally, stop it first)
# password is ‘root’ (see above run command) 
mysql -uroot -p -h 127.0.0.1 -P 3900

In the above steps we pulled the MySQL image provided by Docker and ran a container on top of it. The -p option specifies which local port should be bound to the Docker port. Per the container’s instructions the default MySQL password was passed into the container. At this point there is an active container running a MySQL server. This can be verified with

sudo docker ps

Login into the container and create a new user for the database

mysql -uroot -p -h 127.0.0.1 -P 3900

mysql> CREATE USER 'php'@'%' IDENTIFIED BY 'pass';
mysql> GRANT ALL PRIVILEGES ON *.* TO'php'@'%' WITH GRANT OPTION;
mysql> FLUSH PRIVILEGES;
mysql> exit;

For the Apache, and PHP, container, we can build an image based on a Dockerfile. This could have been done for the MySQL container as well, but the MySQL containers are a bit more complex to set up. Use Docker Hub to view existing containers, and study the Dockerfiles and repos to get a better understanding of how they are built.

The Apache Dockerfile can look like this

FROM ubuntu:14.04

RUN apt-get update
RUN apt-get install -y apache2
RUN apt-get install -y php5 php5-common php5-cli php5-mysql php5-curl 

EXPOSE  80

CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Simply specify the OS, which commands to run to set up the container, which ports to open, and which command to run when the container is started. In this case the Apache service is being ran in the foreground.

From the Dockerfile the image can be built, where the name:tag is specified with the -t option, and the following period specifies where the Dockerfile is located

sudo docker build -t jessecascio/local:apache .

After the image has been built it can be seen with the images command

sudo docker images

Now that image has been created a container can be ran on top of the image. However, since this container is a part of the stack it should be linked to the mysql Docker container.

sudo docker run -d -p 8080:80 --name apache --link mysql:mysql -v /var/www/html:/var/www/html jessecascio/local:apache

# verify the two containers are running, and link exists
sudo docker ps
sudo docker inspect -f "{{ .HostConfig.Links }}" apache

The above run command included the –link option which specifies which container to link to along with an optional alias, and the -v option which maps a local directory to a directory in the container.

It’s important to note that while links are not required they are extremely useful. For example the two containers could be ran separate but when the apache container talks with the mysql container it needs to know the connection information. While this can be hard coded, that is not a good idea as if a container is restarted the connections will be broke. Linking the containers forces Docker to share information about the linked containers via Linux ENV vars and the /etc/hosts file.

Now that the apache server container is running, the following URL will bring up the Apache welcome page in the browser

http://localhost:8080/

Since the /var/www/html directories are linked test.php can be added

# in /var/www/html/test.php
<?php

phpinfo();

Verify in browser

http://localhost:8080/test.php

Lastly verify the containers can communicate by making a database connection with the user which was created earlier.

# in /var/www/html/db.php
<?php

// Could also use getenv('MYSQL_PORT_3306_TCP_ADDR')
// But recommended to use the host entry which survives server restart
$dsn = 'mysql:host='.gethostbyname('mysql');
$usr = 'php';
$pwd = 'pass';

try {
    $dbh = new PDO($dsn, $usr, $pwd);
} catch (PDOException $e) {
    die('Connection failed: ' . $e->getMessage());
}

echo 'Connection made!!!';

The two Docker containers are running and communicating. A two container Docker LAMP stack has been created.

Blog Powered By Wordpress