Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

containerizing an Azure function - changing AzureWebJobsScriptRoot variable from Dockerfile

Tags:

I have a python Azure function with a specific business logic. In the Dockerfile, I want to run the container as a non-root user, so I did the following:

FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8
.
.
.

RUN useradd -u 1001 -m fem-downloader
RUN chown -R 1001:1001 /home/

# I Changed the AzureWebJobsScriptRoot value to this new user path
ENV AzureWebJobsScriptRoot=/home/fem-downloader/wwwroot \
  AzureFunctionsJobHost__Logging__Console__IsEnabled=true

USER fem-downloader
COPY --chown=fem-downloader:fem-downloader requirements.txt requirements.txt

RUN pip install -r requirements.txt
COPY --chown=fem-downloader:fem-downloader .  /home/fem-downloader/wwwroot

WORKDIR /home/fem-downloader/wwwroot/HttpTrigger/

ENV PATH="/home/fem-downloader/.local/bin:/home/.local/bin:${PATH}"

RUN pip install pytest && python3 -m pytest --verbose

When I run the Azure function locally, it works:

docker run -ti -p 8001:80 --name my-azure-function my-azure-function:nonroot

info: Host.Startup[0]
      Found the following functions:
      Host.Functions.HttpTrigger

info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
      Initializing function HTTP routes
      Mapped function route 'api/HttpTrigger' [post] to 'HttpTrigger'

info: Host.Startup[412]
      Host initialized (202ms)
info: Host.Startup[413]
      Host started (211ms)
info: Host.Startup[0]
      Job host started
Hosting environment: Production
Content root path: /home/my-project/wwwroot/HttpTrigger
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.
info: Microsoft.Azure.WebJobs.Script.Workers.Rpc.RpcFunctionInvocationDispatcher[0]
      Worker process started and initialized.
info: Host.General[316]
      Host lock lease acquired by instance ID '00000000000000000000000043EEAD9A'.

Even I test it by sending the parameters its expect:

> curl -X POST http://localhost:8001/ -d "stream_id=XXXX&file_type=SCIA&server_url=https://aaaa.bbbbb.cccccc.digital"
<!DOCTYPE html>
<html>
<head>
    <title>Your Azure Function App is up and running.</title>
    <style type="text/css">
        @font-face {
            font-family: 'SegoeLight';
            src: url(//:) format('no404'), url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAFbcABAAAAAAjewAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABbAAAABsAAAAcWqtaPUdERUYAAAGIAAAAHQAAACABGAADT1MvMgAAAagAAABYAAAAYGrqcLZjbWFwAAACAAAAAaIAAAIKczqUA2N2dCAAAAOkAAAATAAAAEwOEAwRZnBnbQAAA/AAAAGxAAACZQ+0L6dnYXNwAAAFpAAAAAwAAAAMAAMAB2dseWYAAAWwAABJAAAAe3CDYeDNaGVhZAAATrAAAAAxAAAANv

But when I deploy it on Azure, I've checked the logs:

2021-02-12T21:42:12.204812448Z warn: Host.Startup[0]
2021-02-12T21:42:12.205484355Z       No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
2021-02-12T21:42:12.212736520Z info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
2021-02-12T21:42:12.212758420Z       Initializing function HTTP routes
2021-02-12T21:42:12.212763520Z       No HTTP routes mapped
2021-02-12T21:42:12.204812448Z warn: Host.Startup[0]
2021-02-12T21:42:12.205484355Z       No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
2021-02-12T21:42:12.212736520Z info: Microsoft.Azure.WebJobs.Script.WebHost.WebScriptHostHttpRoutesManager[0]
2021-02-12T21:42:12.212758420Z       Initializing function HTTP routes
2021-02-12T21:42:12.212763520Z       No HTTP routes mapped

That socket address error is because the container couldn't manage to initialized, due to the configuration value for AzureWebJobsScriptRoot I provided, I mean the change of the route.

ENV AzureWebJobsScriptRoot=/home/fem-downloader/wwwroot \
  AzureFunctionsJobHost__Logging__Console__IsEnabled=true

Reading on, I found this issue

it doesn't seem like Azure is honoring the AzureWebJobsScriptRoot setting. If I set it to something like D:\home\site\wwwroot\foo, it is still loading functions from D:\home\site\wwwroot (even though I have host.json and function folders under D:\home\site\wwwroot\foo).

The setting seems to work correctly in local environments, but not on Azure.

Looking at the azure function host project, by default the WebHostScriptPath is configured of this way: Data[WebHostScriptPathProperty] = Path.Combine(home, "site", "wwwroot");

The config settings also confirm it.

As they discussed in the issue it seems Azure has good reasons behind to don't allow to change this AzureWebJobsScriptRoot value.


UPDATE

Even I tried by setting this path to the default value, and on the other hand, working with a non-root user giving it permissions over that path (/home/site/wwwroot) in this way without success:

FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8

RUN useradd -u 1001 -m fem-downloader

RUN chown -R 1001:1001 /home/
# ENV AzureWebJobsScriptRoot=/home/fem-downloader/wwwroot \
  # AzureFunctionsJobHost__Logging__Console__IsEnabled=true
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
    AzureFunctionsJobHost__Logging__Console__IsEnabled=true
USER fem-downloader
COPY --chown=fem-downloader:fem-downloader requirements.txt requirements.txt

RUN pip install -r requirements.txt
# COPY --chown=fem-downloader:fem-downloader .  /home/fem-downloader/wwwroot
COPY --chown=fem-downloader:fem-downloader .  /home/site/wwwroot
# WORKDIR /home/fem-downloader/wwwroot/HttpTrigger/
WORKDIR /home/site/wwwroot/HttpTrigger/
# ENV PATH="/home/fem-downloader/.local/bin:/home/.local/bin:${PATH}"
ENV PATH="/home/site/.local/bin:/home/.local/bin:${PATH}"
RUN pip install pytest && python3 -m pytest --verbose

I got the same result when the function is deployed on Azure.

Is highly probably this topic can be managed with permissions, so I decided to check the existing permissions on the directory by getting access to the container created and we got 755, so all permissions for user, execution, and read for group and others:

fem-downloader@cdf0ec64f1ce:~$ pwd
/home
fem-downloader@cdf0ec64f1ce:~$ ls -all
total 48
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 15 12:36 .
drwxr-xr-x 1 root           root           4096 Feb 15 12:36 ..
drwxr-xr-x 3 fem-downloader fem-downloader 4096 Feb 15 12:36 .aspnet
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 15 10:46 .cache
drwx------ 1 fem-downloader fem-downloader 4096 Feb 15 10:47 .local
drwxr-xr-x 3 fem-downloader fem-downloader 4096 Feb 15 12:36 LogFiles
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 12 20:25 fem-downloader

# /home/site directory
drwxr-xr-x 1 fem-downloader fem-downloader 4096 Feb 15 10:47 site
fem-downloader@cdf0ec64f1ce:~$

Checking the permissions privileges for /home/site/ directory:

fem-downloader@cdf0ec64f1ce:~$ stat -c "%a %A" site
755 drwxr-xr-x
fem-downloader@cdf0ec64f1ce:~$

Checking the permissions privileges for /home/site/wwwroot/ directory:

fem-downloader@cdf0ec64f1ce:~/site$ stat -c "%a %A" wwwroot/
755 drwxr-xr-x
fem-downloader@cdf0ec64f1ce:~/site$

The only way I manage to successfully deploy the function on azure was by running my container as a root user:

# Intermediate stage when installing pip packages and other requirements
.
.
FROM mcr.microsoft.com/azure-functions/python:3.0-python3.8

ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
  AzureFunctionsJobHost__Logging__Console__IsEnabled=true

COPY --from=intermediate /usr/local/lib/python3.8/site-packages/ /usr/local/lib/python3.8/site-packages/

ADD requirements.txt /
RUN pip install -r /requirements.txt

ADD . /home/site/wwwroot

WORKDIR /home/site/wwwroot/HttpTrigger/
RUN pip install pytest && pytest --verbose

Then the function manage to contact the storage account to download the resource we are indicating in the request done above:

***"container": "xxxx", "file_name": "PNd5efdCf-SCIA-xxxxxxx.zip", "sas_url": "abc0spec0test0xxxdwblob0.blob.core.windows.net/xxx/PNd5efdCf-SCIA-xxxxxxx.zip?sv=2018-03-28&ss=b&srt=co&sp=r&se=2021-02-12T19%3A45%3A28Z&st=2021-02-12T18%3A40%3A28Z&spr=https&sig=xxxxxxxxxxxxxxxxxx

I just wanted to put here as many details as I can, just to see if perhaps someone has been experienced the same.

Not sure if from a Dockerfile perspective I can do something to cheat Azure configuration settings, looks like not, but the thing is I don't want to run my container as a root user Does it seem there is nothing to do about changing the AzureWebJobsScriptRoot variable?