Preface by JP La Torre, Co-Founder & CEO at Caylent –
Our API is written in Laravel, and we run it in production using Docker. So naturally one of the first tasks we had for George, our new Summer intern, was to familiarize himself with Docker to understand more about our stack. He picked it up fairly quickly, and we decided to turn his experience into what will hopefully become a new series of blog articles, aptly titled the “Intern Series”.
Docker is now “the world’s leading software containerization platform”, providing a platform for you to develop your application without needing to worry about the discrepancies that exist between your development and production/deployment environments. Docker makes use of container technology, which provides much of the functionality of traditional hypervisors (which includes virtual machines) at a fraction of the cost. Essentially, containers are a lightweight alternative to virtual machines for developers to quickly deploy their applications in a production setting. Instead of requiring separate copies of both OS and hardware resources (RAM and CPU) that virtual machines rely on, container technology uses the local OS and hardware by partitioning the resources into separate containers. Each container is thus able to run its own process/application in an isolated environment. Docker’s container technology is also able to provide a supporting environment for development, testing and deployment.
So how does Docker come into play in this article? As Docker streamlines the development and deployment process, I wanted to write a guide to Dockerize (the means by which you ready an application to run inside a Docker container) a simple Laravel application.
A general three step process occurs when you Dockerize any application. First, you’ll need to write a Dockerfile, a text file that contains a bunch of preloaded bash commands to provide the default states for parameters, application and resources. Second, you’ll build that Dockerfile and this will produce a Docker image, a snapshot of the application. Finally, you will run the image, which launches a Docker container that your application runs in.
Now let’s get started!
First, you’ll begin by downloading Docker from https://docs.docker.com/ for either Mac, Linux or Windows. Once you’ve installed Docker (following their instructions), open up a command line/terminal window.
Let’s make a new directory/folder, to house your eventual Dockerfile (we’ll get to this soon) and access the folder. Enter the commands:
mkdir <name of directory of your choice>
example: mkdir helloworld
cd <into the directory you just created>
example: cd helloworld
Now that we’ve set up the directory and cd into it, we can start with the actual Docker related steps!
So go ahead and create a Dockerfile using the command:
Now that you’ve created the Dockerfile, we want to edit it. Go ahead and open up your Dockerfile in your favorite text editor. I personally use Sublime so within the command line, go ahead and type the command:
This should open your Dockerfile within the Sublime text editor and from here and we can begin to write our first Dockerfile so that we can eventually build our first Docker image. You may have noticed at that point that we have not even touched Laravel yet. But no need for alarm, as that’s the brilliance of a Dockerfile: you can script the commands within the Dockerfile to install Laravel. Remember, a Dockerfile is simply a text file that contains a bunch of preloaded bash commands to provide the default states for parameters, application and resources. Let’s check out some of the bash commands, as well as some Docker specific commands, that you can use within your Dockerfile.
(For the curious reader)
Some Docker specific commands briefly listed below.
FROM tells you what the base image your docker container is running. It’s the foundation for the rest of your image to be built on top of.
MAINTAINER simply tracks who the author of the Dockerfile is.
RUN executes command(s) in a new layer and creates a new image. it is often used for installing software packages.
CMD sets default command and/or parameters, which can be overwritten from command line when docker container runs.
ENTRYPOINT configures a container that will run as an executable.
In our case, we’d like to use Ubuntu (version 14.04) as our base image so the command we’d type into the Dockerfile would be:
To attribute authorship, we use the MAINTAIN command as such:
MAINTAINER George J. <email@example.com>
Now that we’ve set the basic foundation of our Dockerfile using FROM and MAINTAIN, let’s use RUN to really get into the meat of the Dockerfile. Below, the RUN command is used to set up the default packages we’d need to install into our container to run our Laravel application (note: && \ signals the RUN command to continue into the next line)
RUN apt-get update && \ apt-get -y install apache2 php5 libapache2-mod-php5 php5-mcrypt php5-json curl git && \ apt-get clean && \ update-rc.d apache2 defaults && \ php5enmod mcrypt && \ rm -rf /var/www/html && \ curl -sS https://getcomposer.org/installer | php && \ mv composer.phar /usr/local/bin/composer
So what exactly are we doing here in the RUN block? We are updating the newest versions of packages and their dependencies, installing apache2, php5, the php library for apache, and other technologies needed for our container. We are also downloading composer and moving it into our usr/local/bin/composer directory for our container to use. Taken as a whole, we have set up an environment in our future Docker container suitable for to begin creating our Laravel application.
After installing all the prerequisite packages, we are using Composer’s (a subsidiary technology used by Laravel) ‘create-project’ function to create a new Laravel application
RUN composer create-project laravel/laravel laravel $LARAVEL_VERSION --prefer-dist --no-interaction && \ php laravel/artisan key:generate && \ chown www-data:www-data -R laravel/storage
After we’ve set up our default Laravel application, it is now important to have our container be receptive to HTTP and HTTPS ports using TCP/IP conventions. To do this, we can implement:
To run our Laravel application on the apache web server we initialized earlier, we need now to provide some default state for the server. This is done by utilizing the command:
CMD [“/usr/sbin/apache2ctl”, “-D”, “FOREGROUND”]
At this point we’ve finished our Dockerfile. For a complete documentation of the Dockerfile we’ve just created, look below.
# Use this as a base image
# Optional: specify the maintainer
MAINTAINER George J. <firstname.lastname@example.org>
ENV LARAVEL_VERSION ~5.1.0
# Run any command on terminal
RUN apt-get update && \
apt-get -y install apache2 php5 libapache2-mod-php5 php5-mcrypt php5-json curl git && \
apt-get clean && \
update-rc.d apache2 defaults && \
php5enmod mcrypt && \
rm -rf /var/www/html && \
curl -sS https://getcomposer.org/installer | php && \
mv composer.phar /usr/local/bin/composer
COPY 000-default.conf /etc/apache2/sites-available/000-default.conf
# Install Laravel
RUN composer create-project laravel/laravel laravel $LARAVEL_VERSION –prefer-dist –no-interaction && \
php laravel/artisan key:generate && \
chown www-data:www-data -R laravel/storage
# Expose necessary ports to the container
#RUN [“chmod”, “+x”, “/setup-laravel.sh”]
CMD [“/usr/sbin/apache2ctl”, “-D”, “FOREGROUND”]
To actually build the Dockerfile into a Docker image, let’s go back into the terminal window and type the command:
docker build <the file path to your directory>
Remember, as my directory was helloworld, the full command would be:
docker build /george/Desktop/helloworld
Docker will immediately build an image for you, which you can see by right away by running the command:
This will show all images on your local computer (that you’ve either created yourself or that you’ve pulled from DockerHub, a GitHub of sorts for Docker images)
If you want to be able to run the Docker image and load your actual application, Laravel in our case, into a container, then you need to find the IMAGEID of your Docker image, which you can do by running the command:
After locating the IMAGEID (which is usually a big number), you can run the command:
docker run -d -P IMAGEID
//example: docker run -d -P 2173891279
-d and -P are simply tags you can include alongside any bash commands that further tell our container, what other features of the run command we want.
-d simply daemonizes it and runs the container in the background
-P finds the next available port for HTTP (80 on container) and HTTPS (443 on container)
Now that we’ve exposed our container to listen to port 80 and port 443, the -P essentially binds each of these ports on the container to a port on your local computer (aka localhost). Go ahead back into terminal and type the command:
Now you’ll be able to see which port your localhost has binded to. It should resemble the form 0.0.0.0.50454, where 50454 is the port. (Here, 50454 is just an example port. You’re individual port could be different).
Now that you’ve located your port, open up your favorite web browser (Safari, Chrome, Firefox, etc) and type in: localhost: PORT where PORT is the value of your port.
In our case, we’d type into our web browser:
Run the local url and you’ll soon see a page with Laravel 5 pop up!