How to Dockerize Laravel Applications
Tags: laravel, docker, backend, tutorial
Published: 2023-08-28 18:38:24


![Docker](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56cxca5gpyfxicbpig1x.png)

One of the most interesting (and sometimes frustrating) aspects of building software lies in deploying them. There are many dependencies, libraries and infrastructure to take note. Docker seeks to provide a uniform and consistent platform on which to deploy applications that would run anywhere with no issues, effectively solving the "it works on my machine" war between developers and testers. It does this by providing "containers", which are isolated shells housing everything an application needs to run, and "images", which is a snapshot of the application itself. 

You need to have Docker Desktop installed and running on your computer to proceed. ([Docker Desktop](https://docs.docker.com/desktop/install/windows-install/))

Let us now build a simple laravel app and make it run in Docker, or "dockerise" it.

1.Install a new Laravel app thus: 

```php
composer create-project laravel/laravel:^8.0 docker-app
 
cd docker-app

php artisan serve
```

2.Create a new folder in the root of the application titled: "apache", create a file inside it: ``000-default.conf`` and paste the following code: 

```php
<VirtualHost *:80>

  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/html/public/

  <Directory /var/www/html>
    AllowOverride All
    Require all granted
  </Directory>

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

</VirtualHost>
```

This means we are using Apache as our webserver and setting up the virtual host configuration to make it work ([What are Virtual Hosts?](https://dev.to/dreywandowski/how-to-host-several-websites-on-a-single-linux-server-1l5b))

3.Create a folder in the root of the application, titled _supervisor_, and then create a file called _docker-worker.conf_. This will serve to always run queues without us manually doing so. Paste the following code in it:
```php
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work --daemon --tries=3
autostart=true
autorestart=true
numprocs=4
stdout_logfile=/var/www/html/storage/logs/worker.log
redirect_stderr=true
```

4.Create another file in the root of the application, titled "start.sh". We would input our cronjobs in this file so that the container will run any cron commands, be it Laravel schedules or just plain old cronjobs. Paste the following code:

```php
#!/bin/bash

# Navigate to the project directory
cd /var/www/html


# Run the desired commands or scripts
CRON_COMMAND="* * * * * /usr/local/bin/php -q -f /var/www/html/artisan schedule:run --no-ansi >> /var/log/cron.log 2>&1"

# Add the cron job command to the crontab
echo "$CRON_COMMAND" | crontab -

# Any other commands or scripts you want to run as part of the cron job

# Exit with a success status code
exit 0

```

5.In the root of the application, create a Dockerfile (with no extension, and paste the following commands:

```php
# Base image
FROM php:7.4-apache


# Install required dependencies
RUN apt-get update && \
    apt-get install -y --fix-missing \
    libzip-dev \
    zip \
    unzip \
    nano \
    curl \
    cron \
    dos2unix

# Install the required version of Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

#Install MySQL driver
RUN docker-php-ext-install pdo_mysql

# Install Supervisor
RUN apt-get install -y supervisor

# Create a Supervisor configuration directory
RUN mkdir -p /etc/supervisor/conf.d

# Copy Supervisor configuration file into the container directory
COPY supervisor/docker-worker.conf /etc/supervisor/conf.d/docker-worker.conf

# Set working directory
WORKDIR /var/www/html

# Copy app files
COPY . /var/www/html   
COPY apache/000-default.conf /etc/apache2/sites-available/000-default.conf

# Adjust PHP memory_limit
RUN echo "memory_limit=512M" > /usr/local/etc/php/conf.d/memory.ini


# Install dependencies
RUN composer install --prefer-dist --no-interaction

# Set file permissions
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache 
RUN chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache 

# Enable Apache modules
RUN a2enmod rewrite

# Configure cron
RUN touch /var/log/cron.log

# Script file copied into container.
COPY ./start.sh /start.sh

# convert to UNIX style
RUN dos2unix /start.sh

# Giving executable permission to script file.
RUN chmod +x /start.sh

# Expose port 80
EXPOSE 80

# Do house-keeping
RUN php artisan config:cache && \
    php artisan route:cache 

# Start Apache server, queue worker and cron service
CMD ["/bin/bash", "-c", "service apache2 start && /start.sh && cron && supervisord -n"]


```
The commands are basically self-explanatory, however I would explain a few: the `` base-image`` directive says what version of PHP we wish to use for the project (head to [PHP Tags](https://hub.docker.com/_/php)) for more, ``# Install required dependencies`` for essential tools we would need to run the container, then we install composer, and also install a driver to allow MySQL run. 

The last command, the most important one, starts the webserver, executes the script file that activates our cron service, and also starts the laravel queue daemon. This is very handy incase you are building an application with jobs and queues and need the daemon to be running continuously while processing jobs.

6.We have now created all that is needed for the docker image. Build the image with the following command and wait for the image to bundle: `` docker build -t docker-app .`` Once done, run the container: `` docker run -p 8000:80 docker-app``, navigate to 127.0.0.1:8000 and see your laravel app running in the container:

![Laravel app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4wlelcvf7wf2o613yfke.png)

 If you have any Laravel schedule activated, you would see the results in your terminal: 
![cron](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2nttzv0skt6g3lqwgn2.png)



7.You can debug the app container by logging on the terminal of the container provisioned by your Docker Desktop application and clicking the icon highlighted

![container](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upm068ysh98u37hdzevf.png) If you prefer CLI management, you can also copy the container name or id provided and logon with the command `` docker exec -it <container_id_or_name> /bin/bash``. This would open up the terminal of your docker container and debug effectively. 

8.Once everything is set up and running fine we can be sure that this application would run anywhere and can push it to Github or whatever code versioning tool employed by your organization, so that your DevOps engineers would pick it up and set up an appropriate pipeline for a continuous deployment.

9.You can stop the container with the following command: `` docker stop <container_name_or_id>``. If your intention is to stop and remove the container then use the command: ``
docker rm <container_name_or_id>``