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:

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.

View application locally

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:

  1. 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.
  2. Create a container image for the project, build, and then run the container locally.
  3. Publish the Docker image to the Azure container registry.
  4. Create an Azure web app and link it with the published container image.
  5. Enable continuous deployment and create a configuration file to build and deploy the container image on CircleCI.
  6. Push the project to GitHub and connect with CircleCI.
  7. 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.

Create registry

On the registry creation page, input the required details.

Create container registry

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.

Enable admin

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

View repository

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.

Create Web app for container

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.

Create web app

From the Docker tab, select the image source and its Docker image.

Select 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.

Laravel app live

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.

Select 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.

Select configuration file

Your first workflow will start running.

Failed wokrflow

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.

Successful workflow

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.


Oluyemi is a tech enthusiast with a background in Telecommunication Engineering. With a keen interest in solving day-to-day problems encountered by users, he ventured into programming and has since directed his problem solving skills at building software for both web and mobile. A full stack software engineer with a passion for sharing knowledge, Oluyemi has published a good number of technical articles and blog posts on several blogs around the world. Being tech savvy, his hobbies include trying out new programming languages and frameworks.

Read more posts by Olususi Oluyemi