Search code examples
pythondjangoazure-web-app-service

Improving Deployment Time for Django Project on Azure Web App


I have a Django project deployed on an Azure Web App (Linux, P2v2, Python 3.10, Django 4.2), which is functioning as expected. However, the deployment time is extremely slow, taking between 15 to 20 minutes to complete even a small change in the code. This is significantly longer than the deployment times I have experienced with other services.

Here is a snippet of the deployment log:

2023-10-31T12:50:59.953Z - Updating branch 'master'.
2023-10-31T12:51:04.983Z - Updating submodules.
2023-10-31T12:51:05.086Z - Preparing deployment for commit id 'XXXXXXXXX'.
2023-10-31T12:51:05.338Z - PreDeployment: context.CleanOutputPath False
2023-10-31T12:51:05.432Z - PreDeployment: context.OutputPath /home/site/wwwroot
2023-10-31T12:51:05.535Z - Repository path is /home/site/repository
2023-10-31T12:51:05.638Z - Running oryx build...
2023-10-31T12:51:05.644Z - Command: oryx build /home/site/repository -o /home/site/wwwroot --platform python --platform-version 3.10 -p virtualenv_name=antenv --log-file /tmp/build-debug.log  -i /tmp/8dbda100b9921ec --compress-destination-dir | tee /tmp/oryx-build.log
2023-10-31T12:51:06.599Z - Operation performed by Microsoft Oryx, https://github.com/Microsoft/Oryx
2023-10-31T12:51:06.614Z - You can report issues at https://github.com/Microsoft/Oryx/issues
2023-10-31T12:51:06.643Z - Oryx Version: 0.2.20230508.1, Commit: 7fe2bf39b357dd68572b438a85ca50b5ecfb4592, ReleaseTagName: 20230508.1
2023-10-31T12:51:06.658Z - Build Operation ID: 10aafab84d551a74
2023-10-31T12:51:06.664Z - Repository Commit : XXXXXXXXXXXXXX
2023-10-31T12:51:06.670Z - OS Type           : bullseye
2023-10-31T12:51:06.677Z - Image Type        : githubactions
2023-10-31T12:51:06.695Z - Detecting platforms...
2023-10-31T12:51:15.575Z - Detected following platforms:
2023-10-31T12:51:15.608Z -   nodejs: 16.20.2
2023-10-31T12:51:15.613Z -   python: 3.10.8
2023-10-31T12:51:15.618Z - Version '16.20.2' of platform 'nodejs' is not installed. Generating script to install it...
2023-10-31T12:51:15.623Z - Version '3.10.8' of platform 'python' is not installed. Generating script to install it...
2023-10-31T12:51:15.811Z - Using intermediate directory '/tmp/8dbda100b9921ec'.
2023-10-31T12:51:15.837Z - Copying files to the intermediate directory...
2023-10-31T12:51:17.447Z - Done in 2 sec(s).
2023-10-31T12:51:17.465Z - Source directory     : /tmp/8dbda100b9921ec
2023-10-31T12:51:17.470Z - Destination directory: /home/site/wwwroot
2023-10-31T12:51:17.487Z - Downloading and extracting 'nodejs' version '16.20.2' to '/tmp/oryx/platforms/nodejs/16.20.2'...
2023-10-31T12:51:17.496Z - Detected image debian flavor: bullseye.
2023-10-31T12:51:18.418Z - Downloaded in 1 sec(s).
2023-10-31T12:51:18.431Z - Verifying checksum...
2023-10-31T12:51:18.465Z - Extracting contents...
2023-10-31T12:51:19.688Z - performing sha512 checksum for: nodejs...
2023-10-31T12:51:19.876Z - Done in 2 sec(s).
2023-10-31T12:51:19.907Z - Downloading and extracting 'python' version '3.10.8' to '/tmp/oryx/platforms/python/3.10.8'...
2023-10-31T12:51:19.913Z - Detected image debian flavor: bullseye.
2023-10-31T12:51:21.326Z - Downloaded in 2 sec(s).
2023-10-31T12:51:21.343Z - Verifying checksum...
2023-10-31T12:51:21.349Z - Extracting contents...
2023-10-31T12:51:23.829Z - performing sha512 checksum for: python...
2023-10-31T12:51:24.147Z - Done in 5 sec(s).
2023-10-31T12:51:24.180Z - image detector file exists, platform is python..
2023-10-31T12:51:24.193Z - OS detector file exists, OS is bullseye..
2023-10-31T12:51:24.298Z - Python Version: /tmp/oryx/platforms/python/3.10.8/bin/python3.10
2023-10-31T12:51:24.305Z - Creating directory for command manifest file if it does not exist
2023-10-31T12:51:24.311Z - Removing existing manifest file
2023-10-31T12:51:24.335Z - Python Virtual Environment: antenv
2023-10-31T12:51:24.341Z - Creating virtual environment...
2023-10-31T12:51:30.102Z - Activating virtual environment...
2023-10-31T12:51:30.114Z - Running pip install...
(like 4 minutes installing python libraries)

2023-10-31T12:55:37.571Z - Not a vso image, so not writing build commands
2023-10-31T12:55:37.576Z - Preparing output...
2023-10-31T12:55:37.586Z - Copying files to destination directory '/tmp/_preCompressedDestinationDir'...
2023-10-31T12:57:07.095Z - Done in 93 sec(s).
2023-10-31T12:57:07.109Z - Compressing content of directory '/tmp/_preCompressedDestinationDir'...
2023-10-31T13:05:28.569Z - Copied the compressed output to '/home/site/wwwroot'
2023-10-31T13:05:28.603Z - Removing existing manifest file
2023-10-31T13:05:28.641Z - Creating a manifest file...
2023-10-31T13:05:28.675Z - Manifest file created.
2023-10-31T13:05:28.684Z - Copying .ostype to manifest output directory.
2023-10-31T13:05:28.695Z - Done in 853 sec(s).
2023-10-31T13:05:29.132Z - Running post deployment command(s)...
2023-10-31T13:05:29.459Z - Generating summary of Oryx build
2023-10-31T13:05:29.588Z - Parsing the build logs
2023-10-31T13:05:29.703Z - Found 0 issue(s)
2023-10-31T13:05:29.884Z - Build Summary :
2023-10-31T13:05:29.973Z - ===============
2023-10-31T13:05:30.067Z - Errors (0)
2023-10-31T13:05:30.163Z - Warnings (0)
2023-10-31T13:05:30.400Z - Triggering recycle (preview mode disabled).
2023-10-31T13:05:30.534Z - Deployment successful. deployer =  deploymentPath = 

As you can see, most of the time is spent in the "Compressing content of directory '/tmp/_preCompressedDestinationDir'" step (853 seconds).

How can I expedite the deployment process? Even if it's not a full deployment, I need a more efficient way to make minor changes to the code if needed.

Investigations:

I have been exploring the App Service's build system, Oryx, and attempted various combinations of the Oryx configurations to optimize the deployment time, but I haven't seen any significant improvements.

I am curious about the necessity of compressing the virtual environment into 'output.tar.gz' only to have it unpacked into a temporary folder later. Is there a way to bypass this compression step?

Additionally, is there a way to modify the variables in the oryx-manifest.toml file? Adding application variable or adding a custom oryx-manifest to my code, both had no effect.

Any insights or suggestions would be greatly appreciated. Thank you!


Solution

  • Approach 1:-

    According to this MS Document Deploying your Azure Web app via Zip deployment is the best way to improve Deployment performance.

    If you have your Azure Django app in github repository you can download the repository as it is as a Zip Folder and then Deploy it in the Azure Web app like below:-

    I Downloaded a sample Django code from this Github repository and deployed it via below Zip command in my Azure Web app:-

    enter image description here

    After your Azure Web app is created Add the below setting in your Web app configuration:-

    Because, with WEBSITE_RUN_FROM_PACKAGE enabled, App Service launches the application straight from the mounted directory and mounts the uploaded package as the read-only wwwroot directory. Refer this SO thread answer on the same.

    enter image description here

    Now login to your Azure account in your terminal set your subscription and run the command below to deploy your Django Web app:-

    az webapp deployment source config-zip --resource-group v-sidrg --name siliconwebappdjango --src C:\msdocs-python-django-webapp-quickstart-main.zip
    

    Output:-

    The Deployment got successful with less than a minute:-

    enter image description here

    Regarding Oryx Build Refer this Blog for more details in understanding Oryx behaviour.

    When you are using Local Git, Bitbucket, External Git, GitHub Actions, Oryx is enabled by default.

    Approach 2:-

    • Use venv and install all your packages in virtua environment, then Deploy your code via the Virtual Environment. This will aid your Web app deployment directly from the venv like below:-
    py -m venv .venv
    .venv\scripts\activate
    pip install -r requirements.txt
    

    Approach 3:-

    Use CI/CD Piplelines to Build and Deploy your Web app via Azure DevOps, Github Actions, Bitbucket etc.

    Azure DevOps:-

    You can send your python code to Azure DevOps Repos and run the below pipeline to Build your Python app and Deploy it in Web app. As soon as new changes are added in your repository your web app deployment pipeline will trigger automatically reducing your time like below:-

    DevOps Pipeline:-

    trigger:
    - main
    
    variables:
     
      azureServiceConnectionId: 'xxxxx035'
    
      
      webAppName: 'webapp-name'
    
      
      vmImageName: 'ubuntu-latest'
    
      
      environmentName: 'appname'
    
     
      projectRoot: $(System.DefaultWorkingDirectory)
    
     
      pythonVersion: '3.10'
    
    stages:
    - stage: Build
      displayName: Build stage
      jobs:
      - job: BuildJob
        pool:
          vmImage: $(vmImageName)
        steps:
        - task: UsePythonVersion@0
          inputs:
            versionSpec: '$(pythonVersion)'
          displayName: 'Use Python $(pythonVersion)'
    
        - script: |
            python -m venv antenv
            source antenv/bin/activate
            python -m pip install --upgrade pip
            pip install setup
            pip install -r requirements.txt
          workingDirectory: $(projectRoot)
          displayName: "Install requirements"
    
        - task: ArchiveFiles@2
          displayName: 'Archive files'
          inputs:
            rootFolderOrFile: '$(projectRoot)'
            includeRootFolder: false
            archiveType: zip
            archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
            replaceExistingArchive: true
    
        - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
          displayName: 'Upload package'
          artifact: drop
    
    - stage: Deploy
      displayName: 'Deploy Web App'
      dependsOn: Build
      condition: succeeded()
      jobs:
      - deployment: DeploymentJob
        pool:
          vmImage: $(vmImageName)
        environment: $(environmentName)
        strategy:
          runOnce:
            deploy:
              steps:
    
              - task: UsePythonVersion@0
                inputs:
                  versionSpec: '$(pythonVersion)'
                displayName: 'Use Python version'
    
              - task: AzureWebApp@1
                displayName: 'Deploy Azure Web App : siliconwebapp098'
                inputs:
                  azureSubscription: $(azureServiceConnectionId)
                  appName: $(webAppName)
                  package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
    

    enter image description here

    Github Actions:-

    You can also Deploy your Python app via Github Actions workflow by connecting your Web app to your Github and saving the workflow to run like below:-

    enter image description here

    After clicking on Save your Github actions deployment will start and your source code from Github repository will be deployed in the web app.

    enter image description here

    The fastest way among these all is Zip Deployment, You can also add zip deployment command in your Github action workflow. In this SO thread answer, I have Deployed .net app but with zip deploy command via Github actions, You can use the same method for python Django web app.

    Approach 4:-

    Dockerize your Django app and Deploy it in Azure web app, As deploying Containerized application is faster and helps in isolating application components.