Azure / azure-functions-core-tools

Command line tools for Azure Functions
MIT License
1.33k stars 437 forks source link

Fails to run on docker image #1358

Closed mebibou closed 5 years ago

mebibou commented 5 years ago

I am trying to install and run it on the docker image as follows:

FROM docker:latest

RUN apk update && apk upgrade && apk add make py-pip
RUN apk add --virtual=build gcc libffi-dev musl-dev openssl-dev python2-dev
RUN pip install azure-cli && apk del --purge build
RUN apk add --update nodejs nodejs-npm
RUN npm i -g azure-functions-core-tools@latest --unsafe-perm true

RUN func -v

But when building the image, it fails at func -v:

Step 7/17 : RUN func -v
 ---> Running in 9d2c97a80c7f
events.js:167
      throw er; // Unhandled 'error' event
      ^

Error: spawn /usr/lib/node_modules/azure-functions-core-tools/bin/func ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:232:19)
    at onErrorNT (internal/child_process.js:407:16)
    at process._tickCallback (internal/process/next_tick.js:63:19)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:282:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)
Emitted 'error' event at:
    at Process.ChildProcess._handle.onexit (internal/child_process.js:238:12)
    at onErrorNT (internal/child_process.js:407:16)
    [... lines matching original stack trace ...]
    at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)
The command '/bin/sh -c func -v' returned a non-zero code: 1

I saw 2 other issues that mention a similar error, but they seem either resolve magically or not on the same os/machine: #1136 and #167

mebibou commented 5 years ago

Note: I tried running chmod 755 /usr/lib/node_modules/azure-functions-core-tools/bin/func before func -v but still have the same issue

ankitkumarr commented 5 years ago

Looks like docker:latest is an alpine image. We currently do not support or publish an alpine compatible package.

You should be able to install dotnet core runtime, maybe from a dotnet docker image. And then, run dotnet /usr/lib/node_modules/azure-functions-core-tools/bin/func.dll to run all your commands.

mebibou commented 5 years ago

Just tried (took the code form this Dockerfile):

FROM docker:latest

RUN apk update && apk upgrade && apk add make py-pip
RUN apk add --virtual=build gcc libffi-dev musl-dev openssl-dev python2-dev
RUN pip install azure-cli && apk del --purge build

ENV DOTNET_VERSION 2.1.11
RUN apk add gcompat libc6-compat\
    && apk add --no-cache --virtual .build-deps openssl \
    && wget -O dotnet.tar.gz https://dotnetcli.blob.core.windows.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-runtime-$DOTNET_VERSION-linux-musl-x64.tar.gz \
    && dotnet_sha512='1eec1ca48827bdd2548ade5e8fad2cfabd806d59a44dc6505b7bbab8dde27ecbdf46238a6245300809eb2a560e6777691fa21e85b38874c8235e4face9580441' \
    && echo "$dotnet_sha512  dotnet.tar.gz" | sha512sum -c - \
    && mkdir -p /usr/share/dotnet \
    && tar -C /usr/share/dotnet -xzf dotnet.tar.gz \
    && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet \
    && rm dotnet.tar.gz \
    && apk del .build-deps

RUN apk add --update nodejs nodejs-npm
RUN npm i -g azure-functions-core-tools@latest --unsafe-perm true

RUN dotnet /usr/lib/node_modules/azure-functions-core-tools/bin/func.dll -v

which gives me the error:

Failed to load 8-��U, error: Error relocating /usr/lib/node_modules/azure-functions-core-tools/bin/libcoreclr.so: gCurrentThreadInfo: symbol not found
Failed to bind to CoreCLR at '/usr/lib/node_modules/azure-functions-core-tools/bin/libcoreclr.so'
The command '/bin/sh -c dotnet /usr/lib/node_modules/azure-functions-core-tools/bin/func.dll -v' returned a non-zero code: 136
ahmelsayed commented 5 years ago

Try this

+ FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS core-tools-build-env

+ RUN wget https://github.com/Azure/azure-functions-core-tools/archive/master.tar.gz && \
+     tar -xzvf master.tar.gz && \
+     cd azure-functions-core-tools-* && \
+     dotnet publish src/Azure.Functions.Cli/Azure.Functions.Cli.csproj --runtime linux-musl-x64 --output /output

FROM docker:latest
RUN apk update && apk upgrade && apk add make py-pip
RUN apk add --virtual=build gcc libffi-dev musl-dev openssl-dev python2-dev
RUN pip install azure-cli && apk del --purge build
RUN apk add --update nodejs nodejs-npm
- RUN npm i -g azure-functions-core-tools@latest --unsafe-perm true
+ # .NET Core dependencies
+ RUN apk add --no-cache ca-certificates krb5-libs libgcc libintl libssl1.1 libstdc++ lttng-ust tzdata userspace-rcu zlib
+ ENV DOTNET_RUNNING_IN_CONTAINER=true \
+    DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true
+ COPY --from=core-tools-build-env [ "/output", "/azure-functions-core-tools" ]
+ RUN ln -s /azure-functions-core-tools/func /bin/func

RUN func -v

see this for dotnet core alpine dependencies https://github.com/dotnet/dotnet-docker/blob/master/2.1/runtime-deps/alpine3.9/amd64/Dockerfile

ahmelsayed commented 5 years ago

and since the change above is building master, you won't get the right version injected. Master branch is always the latest released cli, but the build number is injected during build. You can pass the build number to dotnet publish if you want it set.

mebibou commented 5 years ago

@ahmelsayed thanks that worked I then tried to use func azure functionapp publish ... but it was saying the dotnet framework was not installed so I installed it and published a docker image: https://hub.docker.com/r/mebibou/dind-azure-functions

I'm actually trying to publish Python function apps using Gitlab, who has a Docker in Docker service. I am currently deploying on Travis-CI, which works fine but wanted to move the deployment to a private gitlab server. Using the above image on Gitlab, the deployment uploads 74.88 MB instead of 85.44 MB on Travis-CI, and when running the function apps it returns an error Function host is not running.. After checking on the Azure portal, the functions disappeared. Doesn't look so good

ahmelsayed commented 5 years ago

Sorry I'm trying to understand your scenario. You want to run a CI/CD on gitlab and be able to publish python functions to azure, right?

I'd recommend not using an alpine base if that were the case. The problem with alpine and python is that it doesn't use standard glibc and uses musl-libc instead. a lot of python packages (numpy, tensorflow, etc) would require a compile step for their C/C++ dependencies, and building those on alpine would not produce valid native binaries to run on our Azure host which is Debian based (uses glibc)

The core-tools spins up an instance of mcr.microsoft.com/azure-functions/python:2.0.12493-python3.6-buildenv (Dockerfile), copies your requirements.txt inside then runs

# https://github.com/Azure/azure-functions-core-tools/blob/dev/src/Azure.Functions.Cli/StaticResources/python_docker_build.sh
pip install --target=".python_packages/lib/python3.6/site-packages" -r requirements.txt

That's all to say if you want things to just work in a gitlab environment you can achieve that by this Dockerfile instead

FROM mcr.microsoft.com/azure-functions/python:2.0.12493-python3.6-buildenv

# Install azure-cli
RUN apt-get update && apt-get install apt-transport-https lsb-release software-properties-common dirmngr -y && \
    AZ_REPO=$(lsb_release -cs) && \
    echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | \
        tee /etc/apt/sources.list.d/azure-cli.list && \
    apt-key --keyring /etc/apt/trusted.gpg.d/Microsoft.gpg adv \
        --keyserver packages.microsoft.com \
        --recv-keys BC528686B50D79E339D3721CEB3E94ADBE1229CF && \
    apt-get update && \
    apt-get install -y azure-cli

# Install azure-functions-core-tools
RUN apt-get update && \
    apt-get install -y azure-functions-core-tools

Then your build/publish script that runs in that above container can just be

# cd to WORKING DIR
# Build your python functions
pip install --target=".python_packages/lib/python3.6/site-packages" -r requirements.txt 

# Login into azure 
az login --service-principal -u "$AZURE_SP_ID" -p "$AZURE_SP_KEY" --tenant "$AZURE_SP_TENANT"

# set your default sub (optional)
az account set --subscription $AZURE_SUBSCRIPTION

# publish your functions
func azure functionapp publish {app-name} --no-build
mebibou commented 5 years ago

@ahmelsayed yes that worked perfectly! I added func settings add FUNCTIONS_WORKER_RUNTIME python for good measure (not sure if it is required) and I can now publish on gitlab. This could be added to the official documentation? only an example for Travis is added, which is quite different from this.

mebibou commented 5 years ago

@ahmelsayed continuing on this, I have a package that needs a program in /user/bin to execute: https://pypi.org/project/GDAL/ I managed to install it correctly with pip install --target=".python_packages/lib/python3.6/site-packages" GDAL==2.1.3 --global-option=build_ext --global-option="-I/usr/include/gdal", which does produce a /user/bin/ogr2ogr file, but when running the function app I have the following error:

[Errno 2] No such file or directory: '/usr/bin/ogr2ogr'

I am guessing that running func azure functionapp publish {app-name} --no-build does not include bin files into the published image? is there a way to fix this?

ahmelsayed commented 5 years ago

@mebibou sorry for the delay. No, in general we only assume that what you're publishing is a layer on top of /home/site/wwwroot of the base container we're running. There is no way to modify files elsewhere on the filesystem on startup.

I was looking at enabling custom docker containers for that scenario, though the startup time is very high today and we want to drive it down to something reasonable before enabling custom containers deployment.

I don't know if pip has a way to put these files somewhere that's not /usr/bin. I'm assuming if you're running this on a non-root machine you'd need to sudo the pip install command?

mebibou commented 5 years ago

I'm actually running this completely on Docker directly for now, and I install it using RUN apt-get update && apt-get install -y gdal-bin

mlazowik commented 5 years ago

@mebibou I guess you could move whatever binaries you need to /home/site/wwwroot/{bin, lib} and add those paths to PATH and/or LD_LIBRARY_PATH

mebibou commented 5 years ago

@mlazowik how would I be able to add them to the PATH? @ahmelsayed is there a way to do this on the published docker image?

ahmelsayed commented 5 years ago

I think if you set LD_LIBRARY_PATH as an App Setting it should work, though I'll have to test it to verify.

Setting PATH in App Settings though might mess up things, unless you set the full one, i.e: /usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin.

I think adding a way to prepend PATH and/or LD_LIBRARY_PATH would be useful for a lot of scenarios. I opened https://github.com/Azure/azure-functions-core-tools/issues/1620 to track that.

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.