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)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With