Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot run gRPC protoc in alpine based dotnet SDK

See this github issue: https://github.com/grpc/grpc/issues/18338

See this example repo: https://github.com/slolife/alpine-protoc

If I include the Grpc.Tools 1.19.0 nuget package in a project, which adds a build step <Protobuf Include="Test.proto" />

This works fine if I create a docker image to build and use the microsoft/dotnet:2.2-sdk as the build image. However, if I try to use the alpine based microsoft/dotnet:2.2-sdk-alpine build image, the build fails with the following error message:

/root/.nuget/packages/grpc.tools/1.19.0/build/_protobuf/Google.Protobuf.Tools.targets(263,5): error MSB6003: The specified task executable "/root/.nuget/packages/grpc.tools/1.19.0/tools/linux_x64/protoc" could not be run. No such file or directory [/src/alpine-protoc.csproj]

I confirmed that the protoc file is in the location that the error message is complaining about.

I tried running apk add libc6-compat and re-running the build. This time I got the following error:

/root/.nuget/packages/grpc.tools/1.19.0/build/_protobuf/Google.Protobuf.Tools.targets(263,5): error MSB6006 : "/root/.nuget/packages/grpc.tools/1.19.0/tools/linux_x64/protoc" exited with code 139. [/src/alpine-proto c.csproj]


Update: Output from ldd protoc

~/.nuget/packages/grpc.tools/1.19.0/tools/linux_x64 # ldd protoc
/lib64/ld-linux-x86-64.so.2 (0x7f60935a7000)
libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f60935a7000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7f60935a7000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f60935a7000)
like image 374
slolife Avatar asked Jan 02 '23 04:01

slolife


1 Answers

This seems like a libc compatibility issue - my best guess is that dotnet pulls the mainland, glibc compatible protoc along with grpc.

The No such file or directory error on Alpine when running an executable that is present and accessible, is typical to ld failing to resolve dependant libraries such as libc.so.6.

From ldd protoc output we can see that protoc requires libc.so.6, so it was likely built on Linux with glibc, such as Ubuntu or Debian. The libc6-compat package provides a compatibility layer on top of musl libc, to allow basic glibc functionality, for example, adding the required library files and missing functions. However, it does not provide full glibc compatiblity. Complex applications depending on glibc are not likely to work out of the box when linked against musl libc, at least not without some porting effort.

When you added libc6-compat, protoc was able to link against the musl-glibc compatiblity libraries, libc.so.6 et al, but when run exited with code 139, meaning that it segfaulted (got a SIGSEGV). This is a good indication that you must use it with an actual glibc. One possible reason for this is the default stack size: musl libc creates threads with very small default stack size, around 68kb, whereas glibc threads are created with 2-8MB stacks. For other subtle differences, refer to: https://wiki.musl-libc.org/functional-differences-from-glibc.html.

You could try work around the nuget package incompatility using a simple hack: install the Alpine compatible protobuf compiler, with apk add protobuf; then, replace your protoc with a symlink to /usr/bin/protoc.

Alternatively, you could try installing proper glibc on Alpine, by adding the following to your Dockerfile (thanks to sgerrand and anapsix):

ENV GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc
ENV GLIBC_VERSION=2.28-r0

RUN set -ex && \
    apk --update add libstdc++ curl ca-certificates && \
    for pkg in glibc-${GLIBC_VERSION} glibc-bin-${GLIBC_VERSION}; \
        do curl -sSL ${GLIBC_REPO}/releases/download/${GLIBC_VERSION}/${pkg}.apk -o /tmp/${pkg}.apk; done && \
    apk add --allow-untrusted /tmp/*.apk && \
    rm -v /tmp/*.apk && \
    /usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib
like image 109
valiano Avatar answered Jan 07 '23 01:01

valiano