How to install Laravel in Docker (build Laravel container)

A tutorial to explain how to install Laravel in docker by building a custom container.

Share This Post

We need to say it: simply running your application on a server is not enough. Not anymore, at least. No matter what your application does, it must be portable. You need the ability to move the app from a hosting provider to another effortlessly. You need to release new versions to your users with a click, without having to configure the server each time. Even more, you want to define your server configuration just once, and never do it again. Luckily, we have one great way to do it: docker containers. If you are working on a Laravel application, this post is for you. We will see how to install Laravel in docker. Before you know it, you will have containerized your Laravel application.

Before we start…

As you have guessed, in this article we are talking about how to install Laravel in docker. Of course, this assumes you have some background knowledge of both technologies. This post is for people who already have a Laravel application, or that are working on it, and would like to install it in docker. However, you should be at least familiar with docker.

In case you are, don’t panic. You just need some additional reading first. Here are two resources that will help you start.

Once you grasp these two technologies, you need a Laravel application and a docker-capable host. In other words, a computer or server capable of running docker containers. If you don’t have one, you can install docker on your PC, just follow the tutorial linked above. Another option would be to run containers in the cloud, on AWS or Azure.

Once you have the environment set up, we can start to see how to install Laravel in docker.

How to install Laravel in docker

At the starting point, we have a Laravel project inside a folder. We already have compiled its assets, minified its CSS and rendered its static elements like images. In other words, we have a Laravel application ready to ship. If you open it in your editor, the folder structure will look something like the following.

The structure of a laravel application. We will have to copy these files in our container when we want to install laravel in docker.
The structure of our Laravel application.

As you can see, the name of the application is “backend”, because it is the root folder. Inside that folder, we have many folders you typically find in any Laravel project, like app, config, or database. This app is already working, we only need to package it in a container.

The dockerfile

The dockerfile is at the heart of our Laravel docker build. In fact, it is the file that tells Docker how to build the container with our Laravel application in it. In the docker file, we need to install a webserver to respond to requests, and copy our application inside the folders of our web server. Literally, much easy to do than to say. Take a look at the dockerfile.

FROM php:7.2.10-apache-stretch

RUN apt-get update -yqq && \
    apt-get install -y apt-utils zip unzip && \
    apt-get install -y nano && \
    apt-get install -y libzip-dev libpq-dev && \
    a2enmod rewrite && \
    docker-php-ext-install pdo_mysql && \
    docker-php-ext-configure zip --with-libzip && \
    docker-php-ext-install zip && \
    rm -rf /var/lib/apt/lists/*

RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer

WORKDIR /var/www
RUN chown -hR www-data .

COPY server/default.conf /etc/apache2/sites-enabled/000-default.conf
COPY backend/. /var/www/

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

EXPOSE 80

This is a complete dockerfile, copy and paste. To work, it must be in the same folder of the backend directory. It shouldn’t be inside the backend folder with all the other Laravel files. What does this file do for installing Laravel in docker? We can find out by breaking out the file, line by line. Furthermore, you also need a folder containing the configuration for apache (default.conf) file. You should name this folder server, and it should be outside your backed folder as well. Here you have the configuration.

<VirtualHost *:80>
    ServerName localhost

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/public

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Of course, replace webmaster@localhost with the email address of the server admin.

Dockerfile, line-by-line

The docker file is just a set of commands, that docker will execute in sequence. Here a little explanation on such commands.

Some preliminary installations

FROM php:7.2.10-apache-stretch

With this command, we tell docker to start from an existing docker image, specifically php:7.2.10-apache-stretch. This is a Linux image that comes with Apache web server pre-installed, with PHP 7.2.10. You can find one for any PHP version you need. In this way, we don’t need to take care of installing apache on our own.

RUN apt-get update -yqq && \
    apt-get install -y apt-utils zip unzip && \
    apt-get install -y nano && \
    apt-get install -y libzip-dev libpq-dev && \
    a2enmod rewrite && \
    docker-php-ext-install pdo_mysql && \
    docker-php-ext-configure zip --with-libzip && \
    docker-php-ext-install zip && \
    rm -rf /var/lib/apt/lists/*

Here we install some packages inside the container. This is done when you build the container image, not every time you launch a new container. In other words, you will get the up-to-date packages of the moment when you build the container. This is what we want for predictability if the container was free to update at its wishes some dependencies may break your app. You want to control when things get updated.

A note here. We are installing the PHP MySQL client because we plant to use a MySQL database (docker-php-ext-install pdo_mysql). However, this is just the client. We don’t want to run the database itself of the container. If you are using PostgreSQL, just replace pdo_mysql with pdo_pgsql.

RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer

We install composer to download dependencies. This assumes we don’t have them in the backend/vendor folder. That would be the case if we are running a CI/CD process.

Copying application files

WORKDIR /var/www
RUN chown -hR www-data .

We move to the folder that the webserver uses and ensure the owner will be www-data user. In other words, we are ensuring that apache will have the ability to serve our application.

COPY server/default.conf /etc/apache2/sites-enabled/000-default.conf
COPY backend/. /var/www/

Outside the backend folder, we also have a server folder that contains a default.conf file. This is the configuration we want to provide to apache. We copy it in the right place. Then, we copy our application inside /var/www.

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

We start the apache process. From this moment on, apache is serving the application.

EXPOSE 80

We expose port 80 of the container. In other words, we enable external traffic to enter the container on port 80, and thus reach apache.

Building your container image

Now that you have your docker file, you can simply build it. Go with your command prompt in the root folder containing the dockerfile, the backend and server folders. Then, simply run:

docker build . --tag <a name>

Replace <a name> with a tag you want to give to your image. A good option could be the ID of your build. Now, you can see your container image among the ones you have with docker image ls.

You can also push it to your docker registry, like Docker Hub, with docker push <image name>:<tag>. For example, if your named your image backend and tagged it with 1, you would use docker push backend:1. Easy.

In Conclusion

In this post, we saw how to create the dockerfile for a Laravel application. With it, we know how to install Laravel in docker. Of course, we still have room for improvement here, as we are currently supplying environment variables inside the build (by also copying the .env file). That’s not ideal, because if we change some parameters, like the IP of the database, we need to release a new docker build.

Nonetheless, with this post, we have an idea about what it takes to containerize your application. It’s easy, so I encourage anyone to do it! It will save you much time and pain later because with containers you have predictability. What do you think? Did you manage to put your Laravel application in a container? Let me know in the comments.

Picture of Alessandro Maggio

Alessandro Maggio

Project manager, critical-thinker, passionate about networking & coding. I believe that time is the most precious resource we have, and that technology can help us not to waste it. I founded ICTShore.com with the same principle: I share what I learn so that you get value from it faster than I did.
Picture of Alessandro Maggio

Alessandro Maggio

Project manager, critical-thinker, passionate about networking & coding. I believe that time is the most precious resource we have, and that technology can help us not to waste it. I founded ICTShore.com with the same principle: I share what I learn so that you get value from it faster than I did.

Alessandro Maggio

2019-11-07T16:30:56+00:00

Unspecified

DevOps

Unspecified