Deploying Django on Azure App Service

22.07.2017

I recently spent a few painful hours deploying Django on Azure App Service. Documentation was lacking and I lost way too much time with trivial issues, so here’s a summary of the problems I encountered.

The setup:

  • Linux Development server with Django 1.11.3 on Python 2.7, and MySQL
  • A relatively cheap Azure App Service plan for Python
  • A MySQL database hosted by ClearDB for Azure

Getting the MySQL driver for Django to work on Azure App Service

The standard MySQL driver used in Django is MySQL-python, which needs compiling when installed via pip. Since you can’t install a compiler in your App Service account, you need to provide a compiled version of the library, which means you have two options:

  1. compiling it yourself, or
  2. downloading it from somewhere.

Compiling it on Windows was not an option, so I downloaded a wheel from Christoph Gohlke’s very useful site.

The following was useful to know:

  • If you chose one of the cheaper App Service plans and didn’t fiddle with the configuration, your plan runs 32 bit, and you need one of the packages that end in -win32.whl.
  • MySQL-python looks outdated, but mysqlclient replaces it, so that’s what I used.
  • In your requirements.txt, you can specify the path to a whl file instead of the name of a package. In my case that was mysqlclient-1.3.10-cp27-cp27m-win32.whl, which I had downloaded from the site mentioned above.
  • If on deployment to Azure you get an error about the wheel file (I forgot the exact wording), it could be because your App Service plan runs an old version of pip. In that case navigate the Azure portal maze until you find a usable console, and upgrade pip from the command line. The install went smoothly after that.
  • In order to avoid all the problems with compilation or wheels, you might be tempted to go for a pure python library like PyMySQL. I didn’t go down that route for two reasons:
    1. PyMySQL requires some rather ugly hacks at the top of various files in order to provide the same API as MySQL-python.
    2. In the future, you might want to use packages such as NumPy for which there are no pure Python versions. If so, you will have install packages from wheels anyway, so you might as well figure it out now.

The curious wonders of web.config

If you happen to develop on Windows, it’s probably easiest to just start with the sample Django project that Microsoft provides, and follow along with their tutorials using Visual Studio and whatever tools they recommend. You’ll have better chances of getting a working configuration, including a working web.config, than if you follow some random blogger’s advice from the depths of the internet (irony detected).

Having little experience with IIS, I wasn’t familiar with the strange web.config syntax. Anyway, one thing you need to get right is the appSettings part, which in my case looked like this:

   <appSettings>
     <add key="WSGI_ALT_VIRTUALENV_HANDLER" value="django.core.wsgi.get_wsgi_application()" />                                                                                   
     <add key="WSGI_ALT_VIRTUALENV_ACTIVATE_THIS" value="D:\home\site\wwwroot\env\Scripts\activate_this.py" />                                                                   
     <add key="WSGI_HANDLER" value="ptvs_virtualenv_proxy.get_virtualenv_handler()" />                                                                                           
     <add key="PYTHONPATH" value="D:\home\site\wwwroot" />                                                                                                                       
     <add key="DJANGO_SETTINGS_MODULE" value="src.settings" />
   </appSettings>

Since I was developing on Linux, I didn’t have ptvs_virtualenv_proxy.py in my folder, but I downloaded it from the official example repository. I’m not sure why it’s needed, but it seems to do be doing whatever job it needs to do.

Accessing your MySQL database on ClearDB

Your Azure portal will provide a link to a plain-looking but functional dashboard by ClearDB. That dashboard will give you all parameters you need in the database section of your settings.py, which looks something like this:

'ENGINE': 'django.db.backends.mysql',
'NAME': 'DATABASE-NAME-HERE',
'USER': 'USERNAME-HERE',
'PASSWORD': 'PASSWORD-HERE',
'HOST': 'eu-cdbr-azure-west-b.cloudapp.net',
'PORT': '3306',
'OPTIONS': {'ssl': {'ca':   'ssl/cleardb-ca.pem',
                    'cert': 'ssl/YOUR-RANDOM-CODE-cert.pem',
                    'key':  'ssl/YOUR-RANDOM-CODE-key2.pem'}
           }

The three PEM files used for SSL were also provided for download on the ClearDB dashboard. However, both the mysqlclient library and the actual command line mysql client refused to read the key file:

SSL error: Unable to get private key from ‘ssl/YOUR-RANDOM-CODE-key.pem’ ERROR 2026 (HY000): SSL connection error: Unable to get private key

The issue was that the PEM file containing the private key did not have the exact format required. This was fixed using:

openssl rsa -in YOUR-RANDOM-CODE-key.pem -out YOUR-RANDOM-CODE-key2.pem

The private key file downloaded from ClearDB had the header

-----BEGIN PRIVATE KEY-----

with the file command somewhat helplessly identifying the format as ASCII text. After the conversion using the command above, the header became

-----BEGIN RSA PRIVATE KEY-----

and the file command gave the format as PEM RSA private key.

The infuriating case of failed request tracing on Azure

The unfortunate reality of using Python is that you’ll have to deal with exceptions at runtime. When they happen on the server, it’s crucial to get some visibility into what went wrong, usually in the form of a traceback.

There is this very useful option called Failed request tracing that you can activate on the Azure Dashboard under Diagnostic logs.

Activate Failed request tracing to get tracebacks in the form of XML files.

Activate Failed request tracing to get tracebacks in the form of XML files.

However, the most infuriating thing about this entire Python on Azure experience is that this crucial little option just turns itself off with no warning. Some sources say it happens after 24 hours, but it was clearly less than that in my case. Why doesn’t the user interface say anything about that?

Summary

  • If you have any choice, avoid running code on platforms where the language is clearly not a first-class citizen. Everything sounds great when you read the glossy marketing materials, but a good experience with Python/Django on Azure is clearly not Microsoft’s priority. It’s no surprise then that AWS is a more popular choice than Azure for Django apps.
  • Remember your Python installation on Azure App service could be 32 bit.
  • Try upgrading pip if it has issues installing a wheel file.
  • The fact that a file ends in PEM doesn’t tell you much about the format of its content. If you encounter problems, check the exact format of the file.
Permalink: /blog/deploying-django-on-azure-app-service.html

Die letzten Blogeinträge

Im Archiv finden Sie alle früheren Einträge.

Kontakt