How to create Laravel Docker image
In this guide, you'll learn how to create a Dockerfile from a Laravel application and use it to build a Docker image that you can use in your Continuous Delivery process.
Actions used in this guide:
Introduction
What is Laravel?
Laravel is a popular open source PHP web development framework with an elegant syntax and user-friendly documentation. It follows the Model-View-Controller (MVC) architectural pattern, which helps in creating maintainable and scalable applications, while its robust set of tools and features allow developers to streamline common tasks, such as routing, database management, and authentication.
What is Docker?
Docker is an open-source virtualization method that allows you to automate the deployment, scaling, and management of applications using containerization. Docker makes it easier to create, deploy, and run applications by providing a standardized way to package and distribute software for any operating system. This eliminates the "works on my machine" issue when working across different environments.
- faster and less resource-consuming than traditional VM's
- easy to set up and configure
- a breeze to reuse: pick an existing image as the cornerstone of your setup and install any libraries or packages not bundled with the image
- shareability: you can push images to Docker registries and pull them on other machines, just like you push and pull code from Git
Laravel in Docker
In theory, Dockerization is the process of packaging an application and its dependencies into a Docker container. In case of Laravel applications, this can be translated into the following steps:
- writing a Dockerfile with configuration instructions for the application
- building a Docker image from the Dockerfile and pushing it to the registry
- pulling the image and launching the app on the web server
To check out how the calculator works before baking Laravel into an image, run this command in the repository:
bashphp artisan serve
$
Step 1: Install Docker
Begin with installing Docker Desktop on your machine:
Step 2: Write a Dockerfile
The Dockerfile is a text that defines the contents and launching method of our Docker image. Open a text editor and create a new file Dockerfile
. Populate the file with the following lines and push it to the repository. We are going to break them down one by one later on.
dockerFROM php:8.0 RUN apt-get update -y && apt-get install -y openssl zip unzip git RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN docker-php-ext-install pdo mbstring WORKDIR /app COPY . /app RUN composer install CMD php artisan serve --host=0.0.0.0 --port=8181 EXPOSE 8181
Dockerfile details
Line 1
Just like we mentioned in the introduction, Docker images can be inherited from other users. Using official Docker images guarantees the template is well written and prepared. In this case, we shall use PHP in version 8.0
:
dockerfileFROM php:8.0
Lines 2-4:
These lines cover the installation of tools required to install Laravel: Git, Zip, Unzip, and OpenSSL. Next, we run the installation command and run PHP modules: PDO and mbstring.
dockerfileRUN apt-get update -y && apt-get install -y openssl zip unzip git RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN docker-php-ext-install pdo mbstring
Lines 5-7:
Here we set the working dir in the container to /app
, copy the Laravel application files to it, and install dependencies using Composer:
dockerfileWORKDIR /app COPY . /app RUN composer install
Line 8:
Use CMD
to set the command that will be run when launching the Docker PHP image. In our case, we're going to serve the application with php artisan
set to port 8181:
dockerCMD php artisan serve --host=0.0.0.0 --port=8181
Line 9:
Expose port 8181 outside the launched container. This is the same port our Laravel application is going to use:
dockerfileEXPOSE 8181
Step 3: Build Docker image for your Laravel project
With the Dockerfile in place, we're ready to create the Docker image. Fire up the terminal, go to the directory with the Dockerfile, and run the Docker build command:
bashdocker build -t my-first-image .
$
The -t
parameter is the tag of the Docker image. The dot at the end of the command means that we're going to build the image in the context of the parent directory. In other words, the files that will be copied to the /app
directory in the application container are files from the contextual directory of the build (in this case: repository directory).
Step 4: Run Docker image
Time to run Laravel in Docker! Launch the container with docker run
. Don't forget to add the parameter with the port:
bashdocker run -p 8181:8181 my-first-image
$
http://localhost:8181
.
Sharing images through Docker registry
Once created, a Docker image can be pushed to a Docker registry from which it can be pulled and run by other users. You can create a private registry and serve images from your server, or use a cloud-hosted solution. Currently, the most popular Docker registries are:
- Docker Hub
- Amazon Elastic Container Registry
- Google Artifact Registry
- Azure Container Registry
- DigitalOcean Container Registry
In this part of the guide we'll show you how to add an image to Docker Hub so you can use it on another computer. Here's what you need to do:
- Create a profile on hub.docker.com/ or log in with an existing one.
- Build the Laravel image and tag it with your DH username:
bashdocker build -t [USERNAME]/my-first-image .
$
- Log in to DH with your username and password:
bashdocker login
$
- Push the image to the registry:
bashdocker push [USERNAME]/my-first-image
$
Image loading...
That's it. From now on you can pull and run your Laravel application on any computer with Docker installed. The default docker run
command will automatically pull and run the image from the selected location:
bashdocker run [USERNAME]/my-first-image
$
Image loading...
Adding database with Docker Compose
You can attach database services to your containers using Docker Compose. Docker Compose is a tool which uses a YAML file to define the services, networks, and volumes required for your application.
Below you'll find an example of a docker-compose.yml
file with a definition of a MySQL database. The definition contains the MySQL version, environment variables for the database name, user, and password, and volume mapping to persist the database:
yamlversion: '3' services: app: build: context: . dockerfile: Dockerfile ports: - 8000:80 depends_on: - db db: image: mysql:5.7 environment: MYSQL_DATABASE: laravel MYSQL_USER: laravel MYSQL_PASSWORD: secret MYSQL_ROOT_PASSWORD: secret volumes: - ./data:/var/lib/mysql
Docker in practice: Use cases
So far we've covered the technical process of building and sharing Docker images. Below we share some concrete appliance of Docker in everyday work.
Docker in development
Every developer knows that before you start working on an application you first need to prepare your work environment. This involves a series of pains, including but not limited to:
- installing the framework in version
X
- installing the database in version
Y
- installing the library in version
Z
The more advanced the project, the more dependencies and setup it involves, which considerably prolongs the process of delivering the application. We won't even mention the dependency hell when you're trying to develop two applications with different requirements on one computer.
With Docker, you don't need to write documentation detailing the operating system setup because the entire working environment is defined in the Laravel Dockerfile and safely stored in Git. This means you can go back to any revision of the file in the repository to see how your project evolved.
What's even more convenient, you don't need anything but Docker to run the software on your computer because everything else – frameworks, libraries, dependencies – is stored in the image. What you do is run git clone
, docker build
, and docker run
and the app is already running on your computer.
Docker in QA
Image loading...
The phrase above is bound to appear whenever a tester and a developer discuss a new feature. In reality, 99% of such problems result from compatibility issues between different environments in which the application is run. One developer codes the application on Linux, another one on Mac, and QA runs the tests on Windows. With Docker, the environment is the same for every member of the team: the app is forwarded to QA in the form of a Docker image pre-configured in the Dockerfile.
Docker for dev/stage/production
Usually, the development process is divided into three consecutive environments:
- Development environment – where the actual coding takes place
- Staging environment – where the application is reviewed and tested
- Production environment – where the final version of the application is hosted
Each of these environments is assigned to a separate branch in the repository. When the work in the development
branch is over, it is merged to the staging
branch, where the QA runs their tests. Then, the staging
branch is merged into the master (production
) branch and the application is ready to be reviewed by the client.
With Docker, each environment is described in a separate Dockerfile for every branch. If you change something in the DEV
branch, the STAGE
branch remains in its original state until the changes have been merged.
Continuous Delivery with Buddy
Buddy is a tool that lets you streamline the process of building images and launching Docker containers on a manual trigger or a push to the repository.
Image loading...
Pipeline configuration
Buddy drops configuration-as-code in favor of visual pipelines that can be arranged using preconfigured actions.
All you need to start is a repository with your project:
Create a new pipeline and set the trigger mode to On push. This way the pipeline will update the image on every change in the selected branch:
Image loading...
- Add the Build image action and select the Dockerfile with the description of your app:
Image loading...
- The next action will test the newly built image before it can be pushed to the registry. Add the Run Image action and indicate the previous action as the source of the image:
Image loading...
- Once Builds and tests the image, we can push it to the selected Docker registry. In this example, we'll use Amazon ECR:
Image loading...
- The last action will run
docker pull
anddocker run
on the selected remote:
defaultdocker pull [USERNAME]/my-first-image docker run -d -p 80:80 [USERNAME]/my-first-image
Image loading...
Once ready, make a push to the selected branch, and watch Buddy will perform all the tasks on auto-pilot. Sweet!
Jarek Dylewski
Customer Support
A journalist and an SEO specialist trying to find himself in the unforgiving world of coders. Gamer, a non-fiction literature fan and obsessive carnivore. Jarek uses his talents to convert the programming lingo into a cohesive and approachable narration.