无法在基于 alpine 的 dotnet SDK 中 运行 gRPC 协议
Cannot run gRPC protoc in alpine based dotnet SDK
查看此 github 问题:https://github.com/grpc/grpc/issues/18338
查看此示例存储库:https://github.com/slolife/alpine-protoc
如果我在项目中包含 Grpc.Tools 1.19.0 nuget 包,这将添加构建步骤 <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 与 grpc 兼容 protoc
。
当 运行 存在并可访问的可执行文件时,Alpine 上的 No such file or directory
错误是 ld
无法解析依赖库(如 libc.so.6
)的典型错误。
从 ldd protoc
输出我们可以看到 protoc 需要 libc.so.6
,因此它很可能是在 Linux 上使用 glibc 构建的,例如 Ubuntu 或 Debian。 libc6-compat
包在 musl libc 之上提供了一个兼容层,以允许基本的 glibc 功能,例如,添加所需的库文件和缺少的函数。但是,它不提供完全的 glibc 兼容性。 link针对 musl libc 时,依赖于 glibc 的复杂应用程序不太可能开箱即用,至少在没有一些移植工作的情况下是这样。
当您添加 libc6-compat
时,protoc
能够 link 针对 musl-glibc 兼容性库,libc.so.6
等,但是当 运行以代码 139
退出,这意味着它发生了段错误(得到一个 SIGSEGV)。这很好地表明您必须将它与实际的 glibc 一起使用。一个可能的原因是默认堆栈大小:musl libc 创建的线程具有非常小的默认堆栈大小,大约 68kb,而 glibc 线程是使用 2-8MB 堆栈创建的。其他细微差别参考:https://wiki.musl-libc.org/functional-differences-from-glibc.html.
您可以尝试使用一个简单的 hack 解决 nuget 包不兼容问题:安装 Alpine compatible protobuf 编译器,使用 apk add protobuf
;然后,将 protoc
替换为符号 link 到 /usr/bin/protoc
.
或者,您可以尝试在 Alpine 上安装正确的 glibc,方法是将以下内容添加到您的 Dockerfile(感谢 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
查看此 github 问题:https://github.com/grpc/grpc/issues/18338
查看此示例存储库:https://github.com/slolife/alpine-protoc
如果我在项目中包含 Grpc.Tools 1.19.0 nuget 包,这将添加构建步骤 <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 与 grpc 兼容 protoc
。
当 运行 存在并可访问的可执行文件时,Alpine 上的 No such file or directory
错误是 ld
无法解析依赖库(如 libc.so.6
)的典型错误。
从 ldd protoc
输出我们可以看到 protoc 需要 libc.so.6
,因此它很可能是在 Linux 上使用 glibc 构建的,例如 Ubuntu 或 Debian。 libc6-compat
包在 musl libc 之上提供了一个兼容层,以允许基本的 glibc 功能,例如,添加所需的库文件和缺少的函数。但是,它不提供完全的 glibc 兼容性。 link针对 musl libc 时,依赖于 glibc 的复杂应用程序不太可能开箱即用,至少在没有一些移植工作的情况下是这样。
当您添加 libc6-compat
时,protoc
能够 link 针对 musl-glibc 兼容性库,libc.so.6
等,但是当 运行以代码 139
退出,这意味着它发生了段错误(得到一个 SIGSEGV)。这很好地表明您必须将它与实际的 glibc 一起使用。一个可能的原因是默认堆栈大小:musl libc 创建的线程具有非常小的默认堆栈大小,大约 68kb,而 glibc 线程是使用 2-8MB 堆栈创建的。其他细微差别参考:https://wiki.musl-libc.org/functional-differences-from-glibc.html.
您可以尝试使用一个简单的 hack 解决 nuget 包不兼容问题:安装 Alpine compatible protobuf 编译器,使用 apk add protobuf
;然后,将 protoc
替换为符号 link 到 /usr/bin/protoc
.
或者,您可以尝试在 Alpine 上安装正确的 glibc,方法是将以下内容添加到您的 Dockerfile(感谢 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