Docker is an open-source containerization platform that simplifies the process of building, shipping, and running applications. It enables developers to package their applications into portable containers that can run on any machine with Docker installed, regardless of the underlying operating system or infrastructure.
Docker simplifies the process of setting up and deploying applications. Instead of manually installing dependencies and configuring the environment, developers can use Docker to create a container that includes everything the application needs to run. This container can then be easily deployed to any environment, such as a development, testing, or production server, without having to worry about configuration issues or compatibility problems.
For Laravel applications specifically, Docker can simplify the process of setting up the development environment and deploying the application to production. Developers can use Docker to create a container that includes the necessary components for running Laravel, such as PHP, Apache or Nginx, and the required extensions and packages. This container can then be used to develop the application locally, and later deployed to production without having to worry about compatibility issues.
It would help to know Laravel, Docker, and Linux basics.- In this article, we will explore how to setup Laravel in Docker using two different methods: manually creating a Dockerfile and using Laravel Sail, a command-line interface for managing Laravel's Docker environment.
Pre-requisites: Install Docker
Installing Docker on Windows
Install Docker desktop and Windows Subsystem for Linux (WSL). If WSL does not install via the terminal, get it manually.
Here are the brief steps to be followed:
- Download the Docker Desktop installer from the Docker website.
- Double-click the downloaded file to launch the installer.
- Follow the instructions in the installer to install Docker on your machine.
- Once the installation is complete, open Docker Desktop from the Start menu.
- Docker Desktop will start a Docker engine, which enables you to run Docker containers on your machine.
Installing Docker on macOS
- Download the Docker Desktop installer from the Docker website.
- Double-click the downloaded file to launch the installer.
- Follow the instructions in the installer to install Docker on your machine.
- Once the installation is complete, open Docker Desktop from the Applications folder.
- Docker Desktop will start a Docker engine, which enables you to run Docker containers on your machine.
Installing Docker on Linux
Update the package index on your machine:
sudo apt-get update
Install the necessary packages to allow apt to use a repository over HTTPS:
sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common
Add Docker’s official GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Add the Docker repository to your system:
sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"
Update the package index again:
sudo apt-get update
Install Docker:
sudo apt-get install docker-ce docker-ce-cli containerd.io
Check service status:
Verify that Docker is installed correctly:
sudo docker run hello-world
Now that you have installed docker, let's start to setup Laravel in Docker.
Method-1: Setup Laravel in Docker Manually
Step-1: Create Dockerfile
Next we would need a dockerfile to build the docker image.
Use Composer base image that the Docker image should be built using the official Composer 2.x image. It sets up an intermediate build stage named "composer
" that we'll use to install Laravel.
FROM composer:2 AS composer
Install Laravel using Composer t install a new Laravel project in the /app
directory within the intermediate "composer
" build stage.
RUN composer create-project --prefer-dist laravel/laravel /app
Use PHP-Apache base image to specify that the final Docker image should be built using the official PHP 8.1 image with Apache preinstalled.
FROM php:8.1-apache
Copy Laravel application installed in the intermediate "composer
" build stage to the /var/www/html/
directory in the final Docker image.
COPY --from=composer /app /var/www/html/ COPY --from=composer /usr/bin/composer /usr/bin/composer
Install required dependencies and PHP extensions and enables the PHP PDO MySQL extension.
RUN apt-get update && \ apt-get install -y \ zip \ unzip \ git \ libpq-dev \ && docker-php-ext-install \ pdo_mysql \ && docker-php-ext-enable \ pdo_mysql
Set proper permissions for the storage and bootstrap/cache directories, allowing Laravel to write to these directories.
RUN chown -R www-data:www-data /var/www/html/storage \ && chown -R www-data:www-data /var/www/html/bootstrap/cache
Enable Apache rewrite module and update document root which is required for Laravel's pretty URLs, and updates the document root in the Apache configuration to point to the public directory of the Laravel application.
RUN a2enmod rewrite && \ sed -i 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/000-default.conf
Optimize Laravel application by generating optimized classmaps using Composer and running the php artisan optimize
command.
RUN composer dump-autoload --optimize \ && php artisan optimize
Expose the web server port for the container will listen on port 80, the default HTTP port.
EXPOSE 80
Set the container's entrypoint to apache2-foreground, which starts the Apache web server in the foreground when the container is run.
CMD ["apache2-foreground"]
Here is the final Dockerfile:
FROM composer:2 AS composer RUN composer create-project --prefer-dist laravel/laravel /app FROM php:8.1-apache COPY --from=composer /app /var/www/html/ COPY --from=composer /usr/bin/composer /usr/bin/composer RUN apt-get update && \ apt-get install -y \ zip \ unzip \ git \ libpq-dev \ && docker-php-ext-install \ pdo_mysql \ && docker-php-ext-enable \ pdo_mysql RUN chown -R www-data:www-data /var/www/html/storage \ && chown -R www-data:www-data /var/www/html/bootstrap/cache RUN a2enmod rewrite && \ sed -i 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/000-default.conf RUN composer dump-autoload --optimize \ && php artisan optimize EXPOSE 80 CMD ["apache2-foreground"]
Step-2: Build Docker Image
Build the Docker image using the docker build command. This command takes two arguments: the path to the directory that contains your Dockerfile (. in this case), and a name for the image (my-laravel-app
in this case). Here's an example command:
# docker build -t my-laravel-app .
[+] Building 60.6s (14/14) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 794B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/php:8.1-apache 3.2s
=> [internal] load metadata for docker.io/library/composer:2 1.9s
=> [composer 1/2] FROM docker.io/library/composer:2@sha256:2cf189b2623d0e84bb648512464ae68397fa153d0c28a7fa53ec686915e6f434 0.0s
=> [stage-1 1/7] FROM docker.io/library/php:8.1-apache@sha256:bf1c9169123ff9f025940e6c62d4b02e48451546add38d3a35f85a26fe705285 34.5s
=> => resolve docker.io/library/php:8.1-apache@sha256:bf1c9169123ff9f025940e6c62d4b02e48451546add38d3a35f85a26fe705285 0.0s
=> => sha256:bf1c9169123ff9f025940e6c62d4b02e48451546add38d3a35f85a26fe705285 1.86kB / 1.86kB 0.0s
=> => sha256:c8f1b0ced87a08384880bee3e3c53894e8bb5cd7196bb70816915fb6de632824 12.64kB / 12.64kB 0.0s
...
=> [stage-1 4/7] RUN apt-get update && apt-get install -y zip unzip git libpq-dev && docker-php-ext-install pdo_mysql && docker-php-ext-enable pdo_mysql 15.3s
=> [stage-1 5/7] RUN chown -R www-data:www-data /var/www/html/storage && chown -R www-data:www-data /var/www/html/bootstrap/cache 0.6s
=> [stage-1 6/7] RUN a2enmod rewrite && sed -i 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/000-default.conf 0.6s
=> [stage-1 7/7] RUN composer dump-autoload --optimize && php artisan optimize 2.4s
=> exporting to image 1.7s
=> => exporting layers 1.7s
=> => writing image sha256:fa4912eeee761136f24fa194d8ae259447989e998cbad305d4a4722cc345ac68 0.0s
=> => naming to docker.io/library/my-laravel-app
Step-3: Start Laravel Server
Once the Docker image is built, you can run it using the docker run command. This command takes several arguments, including the name of the image to run (my-laravel-app
in this case) and any additional options or environment variables that you want to pass to the container. Here's an example command:
# docker run -d -p 8080:80 --name my-laravel-container my-laravel-app b7d8d8072556f27b9c2a0b54f8d3cd1a370e6a13f057df7073807d48fa2c067f # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b7d8d8072556 my-laravel-app "docker-php-entrypoi…" 4 seconds ago Up 4 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp my-laravel-container
This command will start the Docker container and map port 80
in the container to port 8080
on your local machine. You can access your Laravel application by visiting http://localhost:8080
in your web browser.
Step-4: Create Docker Compose File
A Docker Compose file is a YAML file that defines services, networks, and volumes for a Docker-based application. It allows you to configure and manage multi-container applications easily. Here's how to set up a Docker Compose file for a Laravel application:
Create a docker-compose.yml
file in the same directory as your Dockerfile with the following content:
version: '3.8' services: app: build: . image: my-laravel-app container_name: my-laravel-app restart: unless-stopped ports: - "8080:80" environment: - APP_ENV=local - APP_DEBUG=true
Key elements of the docker-compose.yml file:
version
: Specifies the version of the Docker Compose file format. We are using version '3.8'.services
: Defines the services that make up the application. In our case, we have a single service named 'app'.build
: Specifies that the current directory should be used as the build context for the Docker image.image
: Names the Docker image that will be created, in this case 'my-laravel-app
'.container_name
: Provides a custom name for the created container, in our example 'my-laravel-app
'.restart
: Configures the restart policy for the container, using 'unless-stopped' to restart the container unless it is explicitly stopped.ports
: Maps the container's port 80 to the host's port 8080, so the Laravel application can be accessed athttp://localhost:8080
.environment
: Sets environment variables for the Laravel application, such as 'APP_ENV
' and 'APP_DEBUG
.
Step-5: Using docker compose to manage Laravel Image
Start your Docker containers using the docker-compose up
command. This will start all the containers defined in your Docker-compose file.
# docker-compose up -d
Creating network "root_default" with the default driver
Creating my-laravel-app ... done
Next you can try to access the Laravel homepage
Customizing the Docker environment
You can customize the Docker environment for your Laravel application by modifying the Dockerfile
and/or docker-composer.yaml
as per your requirement.
In my case, I had to made some customization to add DocumentRoot
in the docker image, here is my updated Dockerfile
RUN composer create-project --prefer-dist laravel/laravel /app FROM php:8.1-apache COPY --from=composer /app /var/www/html COPY --from=composer /usr/bin/composer /usr/bin/composer RUN apt-get update && \ apt-get install -y \ zip \ unzip \ git \ libpq-dev \ && docker-php-ext-install \ pdo_mysql \ && docker-php-ext-enable \ pdo_mysql RUN chown -R www-data:www-data /var/www/html RUN a2enmod rewrite && \ { \ echo 'ServerName localhost'; \ echo '<VirtualHost *:80>'; \ echo ' DocumentRoot /var/www/html/public'; \ echo ' <Directory "/var/www/html/public">'; \ echo ' Options Indexes FollowSymLinks'; \ echo ' AllowOverride All'; \ echo ' Require all granted'; \ echo ' </Directory>'; \ echo '</VirtualHost>'; \ } > /etc/apache2/sites-available/000-default.conf COPY --from=composer --chown=www-data:www-data /app/public/.htaccess /var/www/html/public/.htaccess EXPOSE 80 CMD ["apache2-foreground"]
Stop and remove any existing containers for the Laravel app, if you've already started them before:
docker-compose down
Rebuild the Docker image:
docker-compose build
Start the containers:
docker-compose up -d
The -d
flag is used to run the containers in detached mode, which means they will run in the background.
You can verify it using docker ps
:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
86e2c02bb0b7 my-laravel-app "docker-php-entrypoi…" 3 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp my-laravel-app
Troubleshooting Errors
If your Laravel web application fail to load then you can use docker logs to troubleshoot any issues:
# docker logs my-laravel-app -f
[Thu Apr 20 03:05:54.499588 2023] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.56 (Debian) PHP/8.1.18 configured -- resuming normal operations
[Thu Apr 20 03:05:54.501808 2023] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
localhost:80 172.25.0.1 - - [20/Apr/2023:03:05:59 +0000] "GET / HTTP/1.1" 200 8327 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/112.0"
Here replace my-laravel-app
with your application name or you can also provide the container ID from docker ps
command output. This will give you runtime updates of any activity on the webserver.
Method-2: Setup Laravel in Docker using Laravel Sail
Laravel Sail simplifies interacting with Laravel Docker configuration by providing simple command CLI. The package comes with docker-compose.yml
file and sail
script. The docker-compose.yml
file defines the Docker containers, whereas the sail
script provides the CLI for interacting with the containers.
Some of the Sail commands are install
for publishing docker-compose.yml
file to the root of the application and up
for starting the containers.
Start Docker desktop then install a new Laravel application.
curl -s https://laravel.build/test_app | bash
Sample Output:
We create a new Laravel project called test_app
. The project is created in the current directory before we execute the curl command. During the installation, sail's application containers get built on the local machine. The default services are mysql
, pgsql
, mariadb
, redis
, memcached
, meilisearch
, minio
, selenium
, and mailpit
. You can choose the services to install by attaching them to the with query string. Otherwise, all the services will be pulled.
For example, the following command pulls mysql
, redis
, and selenium
.
curl -s "https://laravel.build/test_app?with=mysql,redis,selenium" | bash
Next, cd
into the project before starting Laravel Sail.
cd test_app && ./vendor/bin/sail up -d
I have started Laravel Sail in a detached mode, meaning the application runs in the background. You can view the running application by searching localhost
on a browser.
The containers are up and running.
You can stop the containers using Laravel Sail's down command.
./vendor/bin/sail down
Note: Although Laravel Sail gets your application up and running quickly, it is suited for a development environment. You may need to configure Docker for robust deployment and production. That entails customizing Dockerfile and docker-compose files to meet the requirements of your Laravel application.
Troubleshooting errors
You may get the following error:
Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:3306 -> 0.0.0.0:0: listen tcp 0.0.0.0:3306: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
That means (MySQL's default) port 3306 is being used by another application.
The error mainly arises when Xampp server runs MySQL and Apache. So, you can close the services and restart Laravel Sail.
Alternatively, you can map the mysql
port to a different destination. For example, open the docker-compose.yml
file and change the port
from
.... mysql: image: 'mysql/mysql-server:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' ....
to
.... mysql: image: 'mysql/mysql-server:8.0' ports: - '3307:3306' ....
Now start Laravel Sail.
# ./vendor/bin/sail up -d
[+] Running 6/6
✔ Container test_app-selenium-1 Started 2.2s
✔ Container test_app-mysql-1 Started 2.4s
✔ Container test_app-redis-1 Started 2.5s
✔ Container test_app-meilisearch-1 Started 2.5s
✔ Container test_app-mailpit-1 Started 2.1s
✔ Container test_app-laravel.test-1 Started
Summary
In this article, we covered two methods to setup Laravel in Docker. The first method involved manually creating a Dockerfile, building a Docker image, starting the Laravel server, creating a Docker Compose file, and using Docker Compose to manage the Laravel image. We also discussed customizing the Docker environment and troubleshooting errors that may arise during the process.
The second method involved using Laravel Sail, a lightweight command-line interface for managing Laravel's Docker environment. We discussed how to install and configure Laravel Sail, as well as how to use it to set up a Laravel application in Docker.
Overall, both methods provide a convenient and efficient way to set up Laravel in Docker, allowing for easy management of the development environment and quick deployment of applications. By following the steps outlined in this article, developers can get up and running with Laravel in Docker in no time.