How does startup commands work on an azure app service

Tubman ,Dave -Dairy One 5 Reputation points
2023-05-11T18:10:19.1966667+00:00

I have an azure app service that was, until friday, working. The reason for this was the ubuntu-latest used in my deploy workflow was updated, and python, when building wheels for pycairo during deploy, errors out. For some reason the ubuntu image no longer has the linux package for cairo, a graphics library.

I have reproduced this issue on an ubuntu instance by running pip install pycairo. Others have run into this issue both in and out of azure https://github.com/pygobject/pycairo/issues/319

The fix would be simple, simply run sudo apt-get install libcairo2-dev. This works on an instance I can access. I am using a git workflow to deploy the container that runs my web app. It would seem that we just need to run that command on the linux container before it runs it's python setup. That python setup is run by Oryx, which does have a pre_build option. Unfortunately, Oryx cannot do sudo commands, and apt-get alone generates a permission error.

According to microsoft docs, there is an Azure Web App feature for this, called startup command . Supposedly, I can put a command under my app service->configuration->general settings. However, this does not appear to work at all. According to the documentation editing that field in the azure portal should cause it to run. It does not. In the aforementioned github thread, they appear to be specifying the command explicitly in their deploy script, sometimes using the reference:

startup-command: ${{ env.AZURE_WEBAPP_STARTUP_COMMAND }}

and sometimes explicitly:

startup-command: 'apt-get install -y build-essential libcairo2-dev'

I have tried both. I have used the start up command in general settings, and also added a configuration variable in my app configuration named AZURE_WEBAPP_STARTUP_COMMAND, as well as the explicit command in my deploy. I have tried it with SCM_DO_BUILD_DURING_DEPLOYMENT set to both true and false. As far as I can tell the feature does not work. How can I get a simple linux command to run in my web apps container before the rest of the deploy happens. Here is my deploy script:



name: Build and deploy Python app to Azure Web App

env:
  AZURE_WEBAPP_NAME: app-django-sandbox-main  # set this to the name of your Azure Web App
  SLOT_NAME: 'dev' # set this to deployment slot
  PYTHON_VERSION: '3.10' # set this to the Python version to use
  NODE_VERSION: '16.x'
on:
  push:
    branches: ['sandbox-dev-deploy']
  workflow_dispatch:

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python version
        uses: actions/setup-python@v4
        with:
          python-version: ${{ env.PYTHON_VERSION }}

      - name: Create and start virtual environment
        run: |
          python -m venv venv
          source venv/bin/activate

      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          pip install -r requirements/test.txt

      - name: Python Stats
        run: |
          pip list --format json >> python_packages.json
          pip list --outdated --format json >> python_outdated.json

      # Optional: Add step to run tests here (PyTest, Django test suites, etc.)

      - name: Git Stats
        run: python utility/collect_git_stats.py
        shell: sh

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: npm install, build
        run: |
          npm install --legacy-peer-deps
          npm run build-prod

      - name: npm outdated
        run: |
          npm outdated --json >> npm_outdated.json
        continue-on-error: true

      - name: Zip
        run: zip release.zip ./* -r
      
      - name: Upload artifact for deployment jobs
        uses: actions/upload-artifact@v3
        with:
          name: python-app
          path: release.zip

  deploy:
    permissions:
      contents: none
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Development'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v3
        with:
          name: python-app
          path: .
          
      - name: Unzip
        run: |
          pwd
          unzip release.zip
          
      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: ${{ env.AZURE_WEBAPP_NAME }}
          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}

When we removed the dependency that breaks it, it deploys without issue. How do I use startup command in azure web apps?

Azure App Service
Azure App Service
Azure App Service is a service used to create and deploy scalable, mission-critical web apps.
8,935 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. VasimTamboli 5,215 Reputation points
    2023-05-11T19:48:30.24+00:00

    The startup command feature in Azure App Services allows you to run custom commands or scripts before your application starts. However, there are a few considerations and limitations to be aware of when using startup commands.

    Supported Platforms: Startup commands are supported for Linux-based App Services. If you're using a Windows-based App Service, this feature may not be available.

    Shell Environment: The startup command runs in a Bash shell environment. Make sure your commands are compatible with Bash syntax.

    Execution Timing: The startup command is executed after the platform has completed its own initialization steps but before your application code starts. This allows you to perform tasks like installing dependencies or configuring your environment.

    In your case, you want to run the command sudo apt-get install libcairo2-dev before the deployment process. To achieve this, you can use the startup command feature in combination with a deployment script.

    Here's an example of how you can modify your workflow to include the startup command:

    1. In your Azure portal, go to your App Service configuration.
    2. Under "General settings," find the "Startup Command" field.
    3. Enter the command bash -c "sudo apt-get install libcairo2-dev && dotnet /path/to/your/app.dll".

    In this example, the && operator ensures that the command dotnet /path/to/your/app.dll is executed only if the installation of libcairo2-dev is successful. Replace /path/to/your/app.dll with the actual path to your application's entry point.

    Save the configuration, and Azure App Service will run the startup command before starting your application.

    Please note that the startup command feature is not designed to perform complex setup tasks or extensive configuration changes. If you require more advanced operations during deployment, consider using a custom deployment script or a build pipeline with tools like Azure DevOps or GitHub Actions.

    Remember to test your deployment workflow thoroughly to ensure that the startup command and deployment process work as expected.

    1 person found this answer helpful.
    0 comments No comments

  2. Tubman ,Dave -Dairy One 5 Reputation points
    2023-05-15T21:21:13+00:00

    So, I got this to work after looking at the log streams. When specifying the startup command, the default behavior changes a little bit. Before I modified the startup command, we had the following:

    "gunicorn --bind=0.0.0.0 --timeout 600 config.wsgi"

    When I removed that and specified a blank startup command, my app started without issue. I can't find a source, but I read somewhere that the app service automatically runs a gunicorn command on deploy/startup. So when I removed it from the startup, it was still running a form of that command, and the app worked. When I added the following to startup command:

    "apt-get install -y libcairo2-dev"

    The app wouldn't finish starting. When I looked in log streams, it would run this command, but then it would finish everything and the log stream would state the app was unresponsive on port 8000, and declare the deployment/startup a failure. Because a value was specified in the startup command, it was not running the gunicorn command automatically. When I added this as the final startup command:

    "apt-get install -y libcairo2-dev &&

    apt-get install -y gcc &&

    gunicorn --bind=0.0.0.0 --timeout 600 config.wsgi"

    Everything worked fine.

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.