I am deploying my Python code to an Azure Function with Python runtime 3.9, using the following yaml pipeline:
trigger:
branches:
include:
- dev
- test
- uat
- prod
pool:
vmImage: ubuntu-latest
stages:
- stage: Build
displayName: Build stage
condition: always()
jobs:
- job: Build_Stage
displayName: Build Stage
steps:
#Define Python Version
- task: UsePythonVersion@0
displayName: "Setting Python version to 3.9"
inputs:
versionSpec: '3.9'
architecture: 'x64'
#Install Python packages
- bash: |
if [ -f extensions.csproj ]
then
dotnet build extensions.csproj --output ./bin
fi
pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
displayName: 'Install Python packages in venv'
#Archive files to create zip folder for the build
- task: ArchiveFiles@2
displayName: 'Archive files to create zip folder for the build'
inputs:
rootFolderOrFile: '$(Build.SourcesDirectory)' #Change to '$(Build.SourcesDirectory)/FolderNameWithFunctionAppInside' if a new parent folder is added
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
replaceExistingArchive: true
#Publish zip to Azure Pipeline
- task: PublishPipelineArtifact@1
displayName: 'Publish zip Package to Azure Pipeline'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
artifactName: $(artifactName)
artifactType: 'pipeline'
#Deploy to DEV
- stage: DEV
displayName: Deploy to DEV
dependsOn: Build
variables:
- group: <my-variable-group>
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/dev'))
jobs:
- job: Deploy
steps:
#Download artifact to make it available to this stage
- task: DownloadPipelineArtifact@2
inputs:
source: 'current'
path: '$(Pipeline.Workspace)'
#Deploy
- task: AzureFunctionApp@1
displayName: Deploy Linux function app
inputs:
azureSubscription: $(azureRmConnection.Id)
appType: 'functionAppLinux'
appName: $(functionAppName)
package: '$(Pipeline.Workspace)/**/*.zip'
deploymentMethod: auto
#Deploy to TEST
- stage: TEST
displayName: Deploy to TEST
dependsOn: Build
variables:
- group: <my-variable-group>
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/test'))
jobs:
- job: Deploy
steps:
#Download artifact to make it available to this stage
- task: DownloadPipelineArtifact@2
inputs:
source: 'current'
path: '$(Pipeline.Workspace)'
#Deploy
- task: AzureFunctionApp@1
displayName: Deploy Linux function app
inputs:
azureSubscription: $(azureRmConnection.Id)
appType: 'functionAppLinux'
appName: $(functionAppName)
package: '$(Pipeline.Workspace)/**/*.zip'
deploymentMethod: auto
#Deploy to UAT
- stage: UAT
displayName: Deploy to UAT
dependsOn: Build
variables:
- group: <my-variable-group>
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/uat'))
jobs:
- job: Deploy
steps:
#Download artifact to make it available to this stage
- task: DownloadPipelineArtifact@2
inputs:
source: 'current'
path: '$(Pipeline.Workspace)'
#Deploy
- task: AzureFunctionApp@1
displayName: Deploy Linux function app
inputs:
azureSubscription: $(azureRmConnection.Id)
appType: 'functionAppLinux'
appName: $(functionAppName)
package: '$(Pipeline.Workspace)/**/*.zip'
deploymentMethod: auto
#Deploy to PROD
- stage: PROD
displayName: Deploy to PROD
dependsOn: Build
variables:
- group: <my-variable-group>
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/prod'))
jobs:
- job: Deploy
steps:
#Download artifact to make it available to this stage
- task: DownloadPipelineArtifact@2
inputs:
source: 'current'
path: '$(Pipeline.Workspace)'
#Deploy
- task: AzureFunctionApp@1
displayName: Deploy Linux function app
inputs:
azureSubscription: $(azureRmConnection.Id)
appType: 'functionAppLinux'
appName: $(functionAppName)
package: '$(Pipeline.Workspace)/**/*.zip'
deploymentMethod: auto
When I trigger this pipeline, my build stage fails with an error message pointing at krb5-config
:
File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 351, in <module>
main()
File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 333, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 118, in get_requires_for_build_wheel
return hook(config_settings)
File "/tmp/pip-build-env-j844587_/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 338, in get_requires_for_build_wheel
return self._get_build_requires(config_settings, requirements=['wheel'])
File "/tmp/pip-build-env-j844587_/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 320, in _get_build_requires
self.run_setup()
File "/tmp/pip-build-env-j844587_/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 335, in run_setup
exec(code, locals())
File "<string>", line 109, in <module>
File "<string>", line 22, in get_output
File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/subprocess.py", line 424, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/subprocess.py", line 528, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command 'krb5-config --libs gssapi' returned non-zero exit status 127.
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.
note: This error originates from a subprocess, and is likely not a problem with pip.
##[error]Bash exited with code '1'.
Is there a way I can fix this?
EDIT
The requirements are as follows:
pip==22.3.1
azure-functions
azure-functions-durable
datetime
requests==2.28.1
arcgis==2.0.1
openpyxl==3.0.10
numpy
I found out that it works if the bash
section of the pipeline is changed from this:
#Install Python packages
- bash: |
if [ -f extensions.csproj ]
then
dotnet build extensions.csproj --output ./bin
fi
pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
displayName: 'Install Python packages in venv'
to this, where the packages making the pipeline fail are installed before the other Python packages:
#Install Python packages
- bash: |
if [ -f extensions.csproj ]
then
dotnet build extensions.csproj --output ./bin
fi
sudo apt install -y libkrb5-dev
pip install requests-kerberos
pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
displayName: 'Install Python packages in venv using inline Bash script'
EDIT
In the event a new Ubuntu image is released without updating the sources, the best course of action is to update the sources before installing the kerb5 packages, like so:
sudo apt-get update && sudo apt-get install -yq libkrb5-dev
#Install Python packages
- bash: |
if [ -f extensions.csproj ]
then
dotnet build extensions.csproj --output ./bin
fi
sudo apt-get update && sudo apt-get install -yq libkrb5-dev
pip install requests-kerberos
pip install --target="./.python_packages/lib/site-packages" -r ./requirements.txt
displayName: 'Install Python packages in venv using inline Bash script'