Deploying Drupal on an Azure App Service Linux Docker Container

From a performance perspective, PHP applications running on Azure App Services tend to perform better on Linux than Windows.  While Azure provides a Drupal template in their Marketplace, it deploys to a regular Windows based App Service and installs version 8.3.3 (where as of the time of writing this article; 9/10/2018, the latest Drupal version is 8.6.1)

In this case, Microsoft has published a set of templates that provide flexibility to choose the Drupal version, deploy nginx, install PHP, and allow flexibility in installing any modules.  The templates are currently deployed and maintenace on GitHub, which can be found here: https://github.com/Azure/app-service-quickstart-docker-images/tree/master/drupal-nginx-fpm

So let's get started!

Download and install prerequisites:

  1. Download and install Git
  2. Download and install Docker
    1. Note: The above link is for Windows, here are the links to the other distributions for Docker: https://store.docker.com/search?offering=community&type=edition
    2. Note: On windows I recommend running the command git config core.autocrlf true to prevent issues with weird character returns.  Check out this awesome blog article by Tim Clem on why this is recommended: https://adaptivepatchwork.com/2012/03/01/mind-the-end-of-your-line/
  3. Download and install Visual Studio Code (free lightweight code editor for Windows, Linux, and Mac)

Note: I'm using a Windows 10 machine while writing this tutorial.  There will be some steps, like running Git Bash on Windows vs running Git natively on Linux.  Likely, you can just run Git from a regular terminal session and you'll be fine on the Linux/Mac side.

Clone the GitHub template

  1. Open up Git Bash
  2. Create a new directory for our project
    1. mkdir Drupal-Azure
    2. cd Drupal-Azure
  3. Clone the GitHub templat
    1. git clone https://github.com/Azure/app-service-quickstart-docker-images.git --config core.autocrlf=input
      1. Note: Unfortunately, we cannot just clone a specific directory easily, we have to download all the files.  This particular GitHub project contains several projects, so it'll be about a 50MB download as a heads up 
      2. Note: The --config core.autocrlf=input is used to prevent windows from using crlf vs lf's for line returns.  If you don't specify this, you might receive the following error if you tried running your docker container after being built:
        1. standard_init_linux.go:190: exec user process caused "no such file or directory"
  4. Navigate into the Drupal directory
    1. cd app-service-quickstart-docker-images/drupal-nginx-fpm/0.45

Modify the scripts to your desire

I personally prefer not to have PHPMyAdmin or MariaDB installed as I will leverage Azure MySQL PaaS services for the database.  In this case, I went ahead and modified the Dockerfile document accordingly.

Build the Docker container

Execute the following command to build your container:

docker build -t jackdrupalregistry.azurecr.io/azuredrupal:test .

Note: The . at the end is needed

Note: When building docker images, the repository name must be lowercase

Create Azure Container Registries

Select All Services -> Azure Container Registries.  Select Add and create a new container registry

Push the Docker container to your Azure Container Registry

  1. Navigate to  All Services -> Azure Container Registries -> Your Registry -> Access Keys
  2. Check Enable for Admin user
  3. Go back to Git Bash and execute the following commands
  4. Login to docker
    1. Execute the command:
      1. docker login jackdrupalregistry.azurecr.io -u yourusername -p yourpassword
  5. Push the image up to Azure Container Registry
    1. Execute the command:
      1. docker push jackdrupalregistry.azurecr.io/azuredrupal:test

Deploy the web app

Navigate to Create a resource -> Web App.  Select Docker as the OS type, select Configure container, and leverage the following settings:

  • Image Source: Azure Container Registry
  • Registry: jackdrupalregistry
  • Image: azuredrupal
  • Tag: 0.45

Navigate to All Services -> App Services -> Your App Service -> Application settings and set WEBSITES_ENABLE_APP_SERVICE_STORAGE to true, and click Save to help ensure data persists.  Essentially, anything you write to /home will persist.  Anything else will be reset when the container gets rebuilt.

Create a MySQL Database

Navigate to All Services -> App Services -> Your App Service -> Properties and write down the Outbound IP Addresses; we will use these later.

Select Create a Service -> Azure Database for MySQL -> Create -> create a blank database

Select Connection security and enter the Outbound IP Addresses from your App Service and click Save

Note: I haven't found a way to get Drupal to allow SSL Connections, which would certainly be a best practice.  In this case, on the same Connection security blade, go ahead and set Enforce SSL Connection to Disabled.  If someone knows how to do this, please put a comment below, so I can update this guide.

Go back to the Overview section and write down the Server admin login name and Server name; we will use these during the Drupal setup

Configure Drupal

At this point, go ahead and browse out to your App Service.  You should have all the necessary details to complete the installation setup.  Once completed, you should see the Welcome to Drupal Side splash page.

Notes:

Email:

Upon installation of Drupal you'll receive an error that Drupal cannot send email.  Azure Web Apps don't allow open relay, so you will need to use a 3rd party mail service like SendGrid or Mailchimp to relay emails.

Helpful docker commands:

docker images

docker run -it azuredrupal:test

docker ps -a

docker rm containeridea

docker rmi image

Other deployment strategies:

In addition to deploying through the portal, you could easily deploy via PowerShell, Azure CLI, or ARM template.  Here's an Azure CLI 2.0 example of how to deploy (note: the script below uses PowerShell variables for demonstration, please substitute those as needed):

$resourceGroupName = "Drupal-Test"
$planName = $resourceGroupName
$appName = $planName
$containerName = "appsvcorg/drupal-nginx-fpm:0.45"
$location = "West US"

az group create -l $location -n $resourceGroupName

az appservice plan create `
    -n $planName `
    -g $resourceGroupName `
    --sku S3 --is-linux 

az webapp create `
    --resource-group $resourceGroupName `
    --plan $planName `
    --name $appName `
    --deployment-container-image-name $containerName

az webapp config appsettings set `
    --resource-group $resourceGroupName `
    --name $appName `
    --settings WEBSITES_ENABLE_APP_SERVICE_STORAGE="true"

az webapp config appsettings set `
    --resource-group $resourceGroupName `
    --name $appName `
    --settings WEBSITES_CONTAINER_START_TIME_LIMIT="600"

# please modify DB settings according to current condition
az webapp config appsettings set `
        --resource-group $resourceGroupName `
        --name $appName `
        --settings DATABASE_HOST="drupaldb.mysql.database.azure.com" `
            DATABASE_NAME="drupaldb" `
            DATABASE_USERNAME="user@drupaldb" `
            DATABASE_PASSWORD="abcdefghijklmnopqrstuvwxyz"

7 thoughts on “Deploying Drupal on an Azure App Service Linux Docker Container

  1. roger

    Hello Jack,

    Great article. However i cant seem to get past the build your docker container step.
    docker build -t jackdrupalregistry.azurecr.io/azuredrupal:test .

    I get the following error... Any idea how to fix?

    + php -r readfile('https://getcomposer.org/installer');
    + php -r if (hash('SHA384', file_get_contents('/tmp/composer-setup.php')) === getenv('COMPOSER_SETUP_SHA')) { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('/tmp/composer-setup.php'); echo PHP_EOL; exit(1); } echo PHP_EOL;
    Installer corrupt
    The command '/bin/sh -c set -ex && php -r "readfile('https://getcomposer.org/installer');" > /tmp/composer-setup.php && php -r "if (hash('SHA384', file_get_contents('/tmp/composer-setup.php')) === getenv('COMPOSER_SETUP_SHA')) { echo 'Installer verified'; } else{ echo 'Installer corrupt'; unlink('/tmp/composer-setup.php'); echo PHP_EOL; exit(1); } echo PHP_EOL;" && mkdir -p /composer/bin && php /tmp/composer-setup.php --install-dir=/usr/local/bin/ --filename=composer --version=${COMPOSER_VERSION} && rm /tmp/composer-setup.php && apk update && apk upgrade && rm -rf /var/cache/apk/*' returned a non-zero code: 1

    Reply
    1. Jack Post author

      Hey Roger,

      Looks like the Azure product group has released a new version 0.45 of the template. Looks like the download for composer may have changed, can you try rerunning through the tutorial to reflect version 0.45? I updated the article to reflect changes from 0.43 and 0.44 to now be 0.45

      Jack

      Reply
  2. roger

    I tried .45 and am getting the following error....
    2018-12-10T04:45:40.428016174Z mv: can't rename '/home/drupal_prj': No such file or directory
    2018-12-10T04:45:40.428183575Z INFO: /home/drupal_prj is exist, clean it ...

    I tried to use the git clone https://github.com/Azure/app-service-quickstart-docker-images.git –config core.autocrlf=input

    however -config core.autocrif=input throws an error fatal: Too many arguments.

    usage: git clone [] [--] []

    Any thoughts?

    Reply
  3. Adnan

    >
    > Note: I haven’t found a way to get Drupal to allow SSL Connections, which would certainly be a best practice. In this case, on the same Connection security blade, go ahead and set Enforce SSL Connection to Disabled. If someone knows how to do this, please put a comment below, so I can update this guide.

    Adding the following snippet in settings.php worked for me:
    $databases['default']['default']['pdo'][PDO::MYSQL_ATTR_SSL_CA] = '/etc/ssl/certs/Baltimore_CyberTrust_Root.pem';

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *