无法在基于 alpine 的 dotnet SDK 中运行 gRPC 协议



请参阅此 github 问题:https://github.com/grpc/grpc/issues/18338

请参阅此示例存储库:https://github.com/slolife/alpine-protoc

如果我在项目中包含Grpc.Tools 1.19.0nuget 包,则会添加一个生成步骤<Protobuf Include="Test.proto" />

如果我创建一个 docker 映像来构建并使用microsoft/dotnet:2.2-sdk作为构建映像,这工作正常。 但是,如果我尝试使用基于 alpine 的microsoft/dotnet:2.2-sdk-alpine生成映像,则构建将失败并显示以下错误消息:

/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]

我确认protoc文件位于错误消息抱怨的位置。

我尝试运行apk add libc6-compat并重新运行构建。这次我收到以下错误:

/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]


更新: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)

这似乎是一个libc兼容性问题 - 我最好的猜测是dotnet拉动大陆,glibc兼容protoc以及grpc。

运行存在且可访问的可执行文件时,Alpine 上的No such file or directory错误是ld无法解析依赖库(如libc.so.6)的典型错误。

ldd protoc输出中我们可以看到 protoc 需要libc.so.6,所以它很可能是在带有 glibc 的 Linux 上构建的,例如 Ubuntu 或 Debian。libc6-compat包在 musl libc 之上提供了一个兼容层,以允许基本的 glibc 功能,例如,添加所需的库文件和缺少的功能。但是,它不提供完全的 glibc 兼容性。依赖于glibc的复杂应用程序在与musl libc链接时不太可能开箱即用,至少没有一些移植工作。

当你添加libc6-compat时,protoc能够链接到 musl-glibc 兼容性库,libc.so.6等人,但是当运行时退出代码139,这意味着它段错误(得到一个 SIGSEGV)。这是一个很好的指示,表明您必须将其与实际的glibc一起使用。其中一个可能的原因是默认堆栈大小:musl libc 创建的默认堆栈大小非常小的线程,大约 68kb,而 glibc 线程是使用 2-8MB 堆栈创建的。有关其他细微差异,请参阅:https://wiki.musl-libc.org/functional-differences-from-glibc.html。

你可以尝试使用一个简单的技巧来解决nuget包不兼容的问题:安装与Alpine兼容的protobuf编译器,使用apk add protobuf;然后,用/usr/bin/protoc符号链接替换你的protoc

或者,您可以尝试在 Alpine 上安装适当的 glibc,方法是将以下内容添加到您的 Dockerfile 中(感谢 sgerrand 和 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

我通过将以下内容添加到我的 Dockerfile 来使其工作

ENV PROTOBUF_PROTOC=/usr/bin/protoc
ENV gRPC_PluginFullPath=/usr/bin/grpc_csharp_plugin
RUN apk add protobuf protobuf-dev grpc

我在树莓派上遇到了这个问题。 此脚本从 raspbian 存储库安装原型编译器,并设置符号链接。

#!/bin/bash
# Get the first occurrence of protoc in PATH directories
protoc_path=$(which protoc)

# Check if protoc exists in PATH directories
if [ -z "$protoc_path" ]; then
echo "protoc not found in PATH. Installing protobuf-compiler..."
sudo apt update && sudo apt install -y protobuf-compiler protobuf-compiler-grpc
# Recheck for protoc
protoc_path=$(which protoc)
if [ -z "$protoc_path" ]; then
echo "Failed to install protobuf-compiler or protoc not found in PATH"
exit 1
fi
fi
proto_plugin_path=$(which grpc_csharp_plugin)
for dir in /root/.nuget/packages/grpc.tools/*/tools/linux_arm64; do
if [ -d "$dir" ]; then
if [ ! -L "$dir/protoc" ]; then
rm -f "$dir/protoc" || true
ln -s "$protoc_path" "$dir/protoc"
fi

if [ ! -L "$dir/grpc_csharp_plugin" ]; then
rm -f "$dir/grpc_csharp_plugin"
ln -s "$proto_plugin_path" "$dir/grpc_csharp_plugin"
fi
fi
done
export PROTOBUF_TOOLS_OS=linux
export PROTOBUF_TOOLS_CPU=arm64
dotnet run 

相关内容

  • 没有找到相关文章