Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions 2.x - How to register bindings? #35

Closed
Morgma opened this issue Oct 10, 2018 · 7 comments
Closed

Functions 2.x - How to register bindings? #35

Morgma opened this issue Oct 10, 2018 · 7 comments
Labels
question Further information is requested

Comments

@Morgma
Copy link

Morgma commented Oct 10, 2018

For functions 2.x, it is requirement to explicitly register any extensions aside from HTTP and Timer. I've found that when running a simple ServiceBusTrigger'd function app within a Docker container, the host fails to load the functions runtime because the required extension isn't installed. It seems to not be enough to have the particular extension NuGet referenced in the function source; it has to be installed into the runtime.

I'm thinking I should install the functions core tools in the image and then run "func install extensions" at the entrypoint. Am I missing a more obvious solution?

@ahmelsayed ahmelsayed added the question Further information is requested label Oct 15, 2018
@ahmelsayed
Copy link
Contributor

How are you creating your docker image?

@GuyHarwood
Copy link

GuyHarwood commented Nov 13, 2018

i have this exact same problem.

all of the 20+ tutorials for functions in a container show the absolute basics - using a HTTP trigger, which doesn't require bindings.

We use queue and table storage bindings, so before we run func host start we need to call func extensions install to install the correct .net core libraries into the local bin folder.

The problem is that the main image mcr.microsoft.com/azure-functions/node:2.0 does not include .net core or the azure function core tools.

Here is our Dockerfile....

FROM mcr.microsoft.com/azure-functions/node:2.0
# next line fails
RUN apt-get update && apt-get install -y dotnet-sdk-2.1

RUN npm i -g azure-functions-core-tools@core --unsafe-perm true

ENV AzureWebJobsScriptRoot=/home/site/wwwroot

WORKDIR /home/site/wwwroot
COPY . .

RUN func extensions install

there are a few things that are not obvious, and need clarification...

  1. what should the entrypoint be? func host start?
  2. .net core install fails...
E: Unable to locate package dotnet-sdk-2.1
E: Couldn't find any package by glob 'dotnet-sdk-2.1'
E: Couldn't find any package by regex 'dotnet-sdk-2.1'

what is the correct way to install it?

@ahmelsayed can you help?

@ahmelsayed
Copy link
Contributor

The correct entrypoint is dotnet /azure-functions-host/Microsoft.Azure.WebJobs.Script.WebHost.dll or run-host.sh as in the base image.

You don't want to run the runtime through the CLI production. The CLI turns off authentication and enables debug mode by default for local development. You probably don't want either of these things in Prod.

Installing extensions currently requires dotnet sdk. (removing the dependency is tracked by Azure/azure-functions-core-tools#367), so if you want to build your project in the docker image, then you can do something like:

FROM mcr.microsoft.com/azure-functions/node:2.0

SHELL ["/bin/bash", "-c"]

WORKDIR /home/site/wwwroot
COPY . .

RUN apt-get update && \
    curl -O https://dot.net/v1/dotnet-install.sh && \
    source dotnet-install.sh --channel Current && \
    rm dotnet-install.sh && \
    npm i -g azure-functions-core-tools@core --unsafe-perm true && \
    func extensions install

ENV AzureWebJobsScriptRoot=/home/site/wwwroot

It's not very nice because there are actually few gotchas, like there are actually 2 dotnets on the path, one under /usr/bin/dotnet, that's just the runtime. and one under /home/.dotnet, which is the SDK and that's the one needed for installing the extensions. I guess I assumed that you'll be copying the bin folder as part of your application, but restoring it in the docker build makes sense so I'll see if I can simplify that flow.

@GuyHarwood
Copy link

Thanks for the info @ahmelsayed

Sounds like it may be best to do the build outside of the container.

Either way, canonical documentation / guidance would be good for this, as i could not find anything that covers this as of Nov 2018.

@GuyHarwood
Copy link

GuyHarwood commented Nov 14, 2018

@ahmelsayed using your example docker file above (thank you), we came up with this...

### STAGE 1: Build ###
FROM node:10.6.0 as builder

SHELL ["/bin/bash", "-c"]

WORKDIR /func-app
COPY . .
RUN yarn install

RUN apt-get update && \
    curl -O https://dot.net/v1/dotnet-install.sh && \
    source dotnet-install.sh --channel Current && \
    rm dotnet-install.sh && \
    npm i -g azure-functions-core-tools@core --unsafe-perm true && \
    func extensions install

### STAGE 2: functions runtime image ###
FROM mcr.microsoft.com/azure-functions/node:2.0

ENV AzureWebJobsScriptRoot=/home/site/wwwroot
COPY --from=builder /func-app /home/site/wwwroot

that way we discard of the intermediary container used to install the bindings, and just use the stripped down 'official' image at runtime.

To run it i use docker run -p 8080:80 -it mtc-functions
which outputs...

Hosting environment: Production
Content root path: /
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.

when i navigate to http://localhost:8080 i see the Your Functions 2.0 app is up and running page, but when i navigate to a http function called diag at http://localhost:8080/api/diag i get ERR_CONNECTION_REFUSED

This was because the auth level was set to function, and changing to anonymous got it working.

How do we call dockerized http functions, without setting the auth level to anonymous ?

@Morgma
Copy link
Author

Morgma commented Nov 19, 2018

@GuyHarwood I apologize for not posting more of detail initially, but honestly, none of my attempts were satisfactory and I never found a soul on any blog or MS documentation that offered any improvement. One of my passes at this was similar to what you have above - I used the functions cli to installs the extensions on a build image, then took the output with extensions .dlls in tow and built a runtime image. It worked locally - but Azure still threw an error that the required extension wasn't installed. Gaps between Azure Functions Runtime, Visual Studio and the Functions CLI seem to cause a lot of grief and devalue the intent of containerizing - insulating your app from the host (Azure).

Also, keep in mind that, at least in my experience, your function apps HTTP bindings will not be listed in other Azure services (Logic Apps, APIM, etc.) natively - you'll have to treat it as a generic HTTP service with no OpenAPI spec. Vanilla Web API may be a step up.

I moved on to building my non-HTTP binding on ASP.NET Core 2.1 WebJobs; will probably move my HTTP functions over eventually. CI/CD from Azure DevOps to AKS is more productive than the guessing games I had to play with Azure Function Apps. Also, I can control my startup, use DI, write functional tests, instrument custom APM and logging, actually see Docker logs, actually access the shell, control my filesystem and scale deployments on demand :)

@Morgma
Copy link
Author

Morgma commented Nov 19, 2018

@GuyHarwood To answer your question specifically about the Authorization Level... you can't run anything other than "Anonymous" (maybe the upcoming "User" will work if you use AAD; making this an even more platform-specific solution). When Debugging in Visual Studio, it calls the Functions CLI and bypasses the authentication filter entirely, but the Docker runtime believes, for all intents and purposes, that it's a real runtime. So if you're coded to use Functions auth, it'll fail because it has no way of verifying a token and you have no way to set it. You'd have to run your container behind some reverse proxy that handled auth - another bid for WebJobs on K8s; or maybe you could set a custom filter to validate a shared key, which also removes the two primary features of Function Apps - discovery and key security.

Most of the guidance out there will just blow this off as a minor issue because in the "scripted" functions you can simply set the auth level in the functions.json and they'll largely ignore that you're running a compiled C# function app. Function App is diluted with so many ways and languages that you'll scarcely see documentation get past the barrage and into the depths.

@Morgma Morgma closed this as completed Nov 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants