Deploy a Dockerized Laravel application
Fullstack Developer and Tech Author
As web applications become more complex, software engineering teams must rely on many different products and services to create the best developer experience. The application development ecosystem has grown beyond version control and hosting deployment. Managing the deployment of new features across all services can create a serious bottleneck in the software development lifecycle. It also introduces the risk of human error.
In this tutorial, I will describe how to deploy a Dockerized Laravel application to Microsoft Azure using GitHub for version control. You will take a previously-built Laravel API project, build a container image out of it, and then push the image to the Azure container registry. Then, you will learn how to create an Azure web service as an application and connect the container image to it.
Microsoft Azure Web Apps is a platform as a service (PaaS) that lets you publish web apps running on multiple frameworks, written in different programming languages. You can then use a CI/CD tool (like CircleCI) to build, test, and deploy web applications for a faster release cycle, more efficient development, and higher-quality code.
Prerequisites
In addition to a basic understanding of Laravel and PHP, you will need the following items to get the most from this tutorial:
- Docker Desktop installed on your local machine — follow Docker’s tutorial for Windows or macOS
- A GitHub account
- A CircleCI account
- An Azure account
Our tutorials are platform-agnostic, but use CircleCI as an example. If you don’t have a CircleCI account, sign up for a free one here.
Cloning the demo project
Clone the sample Laravel project by running this command:
git clone https://github.com/CIRCLECI-GWP/docker-laravel-api.git
Setting up the demo project
Next, go to the root of the new folder you just created. Set up the project by running these commands:
cd docker-laravel-api
composer install
cp .env.example .env
php artisan key:generate
php artisan serve
These commands will change directory into the docker-laravel-api
project from the terminal and:
- Install all the project’s dependencies
- Create a
.env
file and copy the content of.env.example
file into it - Generate an application key
- Run the application
By default, your application will be served to http://127.0.0.1:8000/
. Go to this endpoint to view the .json response.
You can use this command to run the unit tests:
php vendor/bin/phpunit
Reviewing the deployment strategy
Now that you have the application running locally, it is a good time to review your deployment strategy. There is no need for any project code changes other than including the configuration file to set up deployment for CircleCI.
In order, you will need to:
- Create a registry to host your container image on Azure container registry (ACR) and obtain the access key. ACR is a private registry owned by Microsoft for hosting Docker images.
- Create a container image for the project, build, and then run the container locally.
- Publish the Docker image to the Azure container registry.
- Create an Azure web app and link it with the published container image.
- Enable continuous deployment and create a configuration file to build and deploy the container image on CircleCI.
- Push the project to GitHub and connect with CircleCI.
- Deploy the container image to the Azure container registry.
Creating an Azure container registry
If you do not have one already, create an account on Azure. Go to the Azure portal dashboard and click Create a resource.
Next, select Containers, then Container Registry to create a new registry.
On the registry creation page, input the required details.
Note: You can create a new resource group for this project or use an existing one.
Click Review + Create. You will be redirected to a page where you can review the registry information. Click Create to set up a new registry instance.
Getting an access key from the registry
In this section, you will enable Docker access in the Azure container registry. This step is crucial to the deployment process. Enabling Docker access lets you log into the Azure container registry remotely through the CLI and push images to it.
Open the registry and locate the Access Keys link under the Settings section.
This will show you the registry name and login server. Use the toggle button to enable the admin user. Then, copy the username and any of the passwords, preferably the first one. Keep this somewhere handy; you will need it later on in the tutorial.
Containerizing the application locally
Your next step is writing a custom Docker file that will allow you to build a container image. From the root of the application, create a new file named Dockerfile
. Open the file and paste this content into it:
FROM php:8.0.20
RUN curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/local/bin --filename=composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get install -y zlib1g-dev \
libzip-dev \
unzip
RUN docker-php-ext-install pdo pdo_mysql sockets zip
RUN mkdir /app
ADD . /app
WORKDIR /app
RUN composer install
CMD php artisan serve --host=0.0.0.0 --port=8000
EXPOSE 8000
PHP version 8 is used as the base image. The subsequent commands install composer, the extensions for a Laravel application, and enable the PHP PDO and MySQL extensions.
When the installation is complete, set the working directory to app
and copy the files from your local machine into the working directory of the container. Then run composer install
and include the command to run the application.
Building the Docker image
To build a Docker image for the project, run:
docker build -t laravelapidocker.azurecr.io/laravelapidocker:latest .
If you are using a the new Mac with M1 or M2 processor, run this command instead:
docker build --platform linux/amd64 -t laravelapidocker.azurecr.io/laravelapidocker:latest .
This command will look in the project for the Dockerfile and build the container image based on the contained instructions. Notice that the command uses the registry name and login server from the registry created earlier. The benefit of this approach is to easily map the container image with the Azure container registry.
Running the Docker image
Now that you have successfully built the local version of the container image, make sure it works. Run:
docker run -d -p 8000:8000 laravelapidocker.azurecr.io/laravelapidocker
This will run the app on port 800
. Check it by visiting http://localhost:8000
.
Pushing the Docker image to Azure Registry
Next, log into the Azure container registry created earlier and push the container image to it. From the terminal, run:
echo DOCKER_PASS | docker login laravelapidocker.azurecr.io -u laravelapidocker --password-stdin
Replace the placeholders with your own values:
DOCKER_USER
: The username obtained for the container registry.DOCKER_PASS
: The password from the container registry.
After you log in, push the image to the Azure registry by running:
docker push laravelapidocker.azurecr.io/laravelapidocker:latest
Creating an Azure web app for the container
Next, you need to create an Azure Web App and connect it with the container image. Go to the Azure portal homepage and click Create a resource.
Select Containers, then Web App for Containers to create a new web app service instance.
You will be redirected to the Create Web App page. Select an Azure subscription and a resource group. Create a new resource group if you need to. Docker container
should be selected by default, if it is not, click to select it.
From the Docker tab, select the image source and its Docker image.
When you click Review + Create, you will be redirected to a page where you can review the web app details. Click Create to set up a new Azure web app.
When the process is completed, you can visit the URL, to review the app as deployed to Azure.
Enable continuous deployment
Each time your Docker image is updated, you want the app to receive the update. To do this, you need to enable continuous deployment for the web app service.
Click on the web app name, then click Deployment Center. On the Settings tab, scroll to the Continuous Deployment button and click to select it. Click Save to persist the changes.
With continuous deployment selected, the web app will trigger a new deployment of the Laravel application each time the Docker image is rebuilt on the Azure container registry.
Automating the deployment
In this step, you will add the pipeline configuration for CircleCI. This pipeline automates testing and runs the commands that build and push the container image to the Azure container registry.
At the root of your project, open the .circleci/config.yml
file. Update its content as shown here:
version: 2.1
orbs:
docker: circleci/docker@2.4.0
jobs:
build-and-test:
description: Setup laravel application and run tests
docker:
# Specify the version you desire here
- image: cimg/php:8.0-browsers
steps:
- checkout
- run:
name: "Prepare environment"
command: |
sudo apt update
# Download and cache dependencies
- restore_cache:
keys:
# "composer.lock" can be used if it is committed to the repo
- v1-dependencies-{{ checksum "composer.json" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-
- run:
name: "Install dependencies"
command: composer install -n --prefer-dist
- save_cache:
key: v1-dependencies-{{ checksum "composer.json" }}
paths:
- ./vendor
- run:
name: "Create .env file and generate app key"
command: |
mv .env.example .env
php artisan key:generate
- run:
name: "Run tests"
command: php vendor/bin/phpunit
build-docker-image:
executor:
name: docker/docker
tag: "3.6"
steps:
- checkout
- docker/install-docker-tools
- setup_remote_docker:
version: 20.10.14
docker_layer_caching: true
- run:
name: "Build and push Docker image"
command: |
docker build -t laravelapidocker.azurecr.io/laravelapidocker:latest .
echo $DOCKER_PASS | docker login laravelapidocker.azurecr.io -u $DOCKER_USER --password-stdin
docker push laravelapidocker.azurecr.io/laravelapidocker:latest
workflows:
test-and-deploy:
jobs:
- build-and-test
- build-docker-image:
requires:
- build-and-test
Here is a breakdown of the configuration.
The CircleCI configuration always starts with the version. For this tutorial, you are using version 2.1
.
The next part of the configuration specifies two different jobs:
build-and-test
build-docker-image
The build-and-test
job uses the CircleCI PHP 8 Docker image, checks out your project from GitHub, installs the project’s dependencies, sets up the environment variables, and runs the application’s tests.
The build-docker-image
job creates a Docker image for the code pulled from the Github repository and updates the Azure container registry with the latest version of the container. The requires
key specifies that the build-docker-image
does not run until the build
job is complete.
Connecting the application to CircleCI
Now you need to set up a repository on GitHub and link the project to CircleCI. Review Pushing a project to GitHub for instructions.
Log into your CircleCI account. If you signed up with your GitHub account, all your repositories will be available on your project’s dashboard.
Click Set Up Project next to your docker-laravel-api
project.
You will be prompted to either write a new configuration file or use the existing one in your project. Select the existing one and enter the name of the branch where your code is housed on GitHub. Click Let’s Go.
Your first workflow will start running.
The build-docker-image
job will fail because you have not yet provided your Azure container registry credentials.
To fix that, you will need to add username and password environment variables. Click Project Settings, then Environment Variables. Create these variables:
- The
DOCKER_USER
variable is the username obtained for the container registry. - The
DOCKER_PASS
variable is the password from the container registry.
Go back to the dashboard. Click Rerun Workflow from Start.
This time, your workflow will run successfully.
Now you can make changes to the codebase locally and push it to GitHub using continuous deployment.
Conclusion
And there you have it. Using Docker, CircleCI, and Microsoft Azure you were able to automate the deployment process of a Laravel application. You performed the set-up process to ensure that, each time you update the project and push the changes to GitHub, CircleCI will use the configuration details to build a new container image and update the associated Azure container registry. And with continuous deployment enabled on the Azure web app, a webhook resource will be fired to push a new version of the container image to the web app.
I hope that you found this tutorial helpful. Check here for the complete source code of the project you built.