Develop Laravel Apps using Docker

As more and more applications are getting deployed to containers, it is very helpful to start developing apps on containers itself. This practice makes sure that you capture every dependency to deploy and run your application in different environments.
One of the biggest advantage of containers is that you don't need to install anything on your local system. You just need to use the base image and customize that according to your requirements.
This is quick article on how to setup Laravel app on Docker. Let's dig into it.

My application has two parts:

Now we have to create two files required for docker setup.
First, lets create a Dockerfile for frontend and lets call it web.Dockerfile.

FROM php:7
RUN apt-get update -y && apt-get install -y openssl zip unzip git libzip-dev zlib1g-dev
RUN curl -sS | php -- --install-dir=/usr/local/bin --filename=composer
RUN docker-php-ext-install pdo pdo_mysql zip
WORKDIR /var/www/app
RUN composer install
CMD php artisan serve --host= --port=80

I'm using php v7 image from docker hub. Then I'm extending that image and updating the container and installing some OS level modules.
Next, I'm installing Laravel in the container using composer. I'm also installing php extensions for mysql and zip in the container.
Then I set the working directory to /var/www/app, this is where my laravel app gets installed.
Finally, I started the built-in web server using php artisan serve command running on port 80 and then exposed port 80 out of the container.
It is worth mentioning that this is not recommended for Production workloads. You can easily setup Apache or Nginx instead of default server for production workloads.

Now we need to create a docker image out of this file and push it to docker hub registry.

docker build -f web.Dockerfile
docker tag <source_image>:<tag> <destination_image>:<tag>
docker push <repo_url>/<image>:<tag>

Now let's create our second file which is called docker-compose.yaml. It will help us in binding frontend and backend components. As you may notice we don't have any database configured yet. So let's create docker-compose.yaml and setup database service.

version: '3'
      context: ./
      dockerfile: web.Dockerfile
      - c:/code/myapp:/var/www/app
    image: <dockerhubrepo>/laravel:v1 #replace <dockerhubrepo> with your docker repository name
      - "DB_PORT=3306"
      - "DB_HOST=database"
      - database
      - 8000:80
    image: mysql:5.6
      - data:/var/lib/mysql
      - "MYSQL_DATABASE=laravel"
      - "MYSQL_USER=someuser"
      - "MYSQL_PASSWORD=somepassword"
      - "MYSQL_ROOT_PASSWORD=rootpassword"
      - 3306:3306

I'm defining two services in this file. First is called web. It used the image that we pushed to docker hub repository in the previous step. I'm also mounting container directory /var/www/app to local directory c:/code/myapp. This will make sure that changes made locally get reflected in the container. Next, it refers database host using variable DB_HOST and database port using DB_PORT. I have also configured the dependency on database service so that database service runs before web service. Finally, I mapped host port 8000 with container port 80.

The second service is called database. This is the name which is refered by web service using DB_HOST variable. I'm pulling the official mysql image straight from docker hub. That's why we don't need separate Dockerfile for database. I'm creating a persistent volume by the name data and mounting it inside container at /var/lib/mysql mount point. Next, I specify serveral database related parameters like database name, user name, user password and root password.
Once you've both of these files ready, run following command to spin up everything.

docker-compose pull #It will pull both images from docker hub
docker-compose up #It will bring up the containers

And that't it!!! You would have your Laravel app up and running on http://localhost:8000. You can continue editing your code locally which is mounted at c:/code/myapp and changes will be pushed to container immediately.