在 .NET Core Docker 映像中包含共享 C 库 (.SO)

Posted

技术标签:

【中文标题】在 .NET Core Docker 映像中包含共享 C 库 (.SO)【英文标题】:Including Shared C Library (.SO) in a .NET Core Docker Image 【发布时间】:2021-06-12 02:04:45 【问题描述】:

我正在尝试在我的 .net Core 5.0 项目中使用 C# 库,它是 C Assembly for ws281x LED 的 C# 包装器。该库要求在运行框架之前构建Shared C library (ws2811.so)。我已经为我的树莓派成功构建并安装了 C 共享库到 /usr/lib 中,并对其进行了测试以确认它可以正常工作。

问题在于在我的 Dockerfile 中,我不知道如何/在哪里正确安装此共享 C 库。我目前的dockerfile如下:

# https://hub.docker.com/_/microsoft-dotnet
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /source
COPY ./ /source

# installs NodeJS and NPM
RUN apt-get update -yq && apt-get upgrade -yq && apt-get install -yq curl git nano
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -yq nodejs build-essential

RUN npm install -g npm
RUN npm --version

# installing c wrapper for ws2811 -- Here is where I need HELP
RUN apt-get update && apt-get install -y python
RUN apt-get install -y python-setuptools python-dev build-essential python-pip

RUN pip install scons && git clone https://github.com/jgarff/rpi_ws281x.git \
         && cd rpi_ws281x && scons && gcc -shared -o ws2811.so *.o

# copy csproj and restore as distinct layers
COPY *.sln .
COPY control/ *.csproj ./control/
RUN dotnet restore -r linux-arm

# copy everything else and build app
COPY control/. ./control/
WORKDIR /source/control
RUN dotnet publish -c release -o /app -r linux-arm --self-contained false --no-restore

# final stage/image
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim-arm32v7
WORKDIR /app
COPY --from=build /app ./
ENTRYPOINT ["./control"]

就像现在一样,dockerfile 正确构建并且应用程序启动。但是,当我尝试使用方法通过 P/Invoke 调用 ws2811.so 库时,出现以下错误:

System.DllNotFoundException: 无法加载共享库“ws2811.so”或其依赖项之一。为了帮助诊断加载问题,请考虑设置 LD_DEBUG 环境变量:libws2811.so: cannot open shared object file: No such file or directory

这告诉我 P/Invoke 未能成功找到 ws2811.so 库。我应该把这个 ws2811.so 库放在哪里,以便我的 C# 代码可以访问它?我已经尝试将它与源代码一起放置,我已经在 docker 中安装它,但我真的处于停滞状态,不知道从哪里开始。

有关更多信息,调用此 C 共享库的 C# 代码如下。它基本上与 ws281x GitHub 上的示例中所做的相同(如前所述)。

public void setRgb()
        
            Console.WriteLine("R: " + r + "\tG: " + g + "\tB: " + b);

            var settings = Settings.CreateDefaultSettings(false);
            var controller = settings.AddController(88, Pin.Gpio18, StripType.WS2812_STRIP, 255, false);

            Color color = new Color();
            color = Color.FromArgb(r, g, b);

            using (var rpi = new WS281x(settings)) // EXCEPTION OCCURS HERE (System.DllNotFound)
            
                rpi.SetLedCount(88);
                rpi.SetAll(color);
            
        

非常感谢任何帮助、指导或资源!非常感谢:)

【问题讨论】:

第一条评论:共享库是否存在于您的最终容器映像中? (您正在使用多阶段构建,其中每个容器可能包含也可能不包含来自前一个容器的位)。其次,对于可能的位置,您可以将其放在与应用程序dll相同的位置; DllImport 可以/应该从当前工作目录中获取共享库。 我在 Docker 上是个菜鸟,这实际上就是我想要做的,将共享库放入最终的容器映像中。我使用 scons 和 GCC 构建它,但我不确定如何将它包含在图像中。我该怎么做呢?另外——我会尝试将它放在当前工作目录中并回复您。非常感谢。 您只是将已发布的应用程序复制到最终的 docker 映像 COPY --from=build /app ./ 并且该源目录没有您的 SO,因为 dotnet publish 不会把它放在那里。您需要将最终位复制到最后一个阶段 这对我来说很有意义,我只是不知道如何将 ws2811.so 实际复制到最终的 docker 映像中。当我尝试将 ws2811.so 复制到 ./ 时,我收到一条错误消息,告诉我 ws2811.so 无处可寻。如何从我的构建文件夹 (/rpi_ws281x) 中获取 .so 文件并将其放入最终暂存区? 【参考方案1】:

Docker 有“构建上下文”的概念。这定义了从中访问文件的目录。因此,当您在 Dockerfile 中说 COPY foo /foo 时,就是从构建上下文中复制 foo 文件并将其放置在名为 foo 的容器的根文件夹中。在运行docker build 命令时设置构建上下文。很多时候,人们使用. 作为构建上下文,这意味着您正在从中运行命令的当前工作目录(例如docker build -t app .)。所以这取决于你的构建上下文是什么目录。这就是您应该放置 .SO 库的位置,以便您可以在 Dockerfile 中添加 COPY 指令,将其复制到您的容器映像中。

【讨论】:

这成功了!非常感谢您的清晰解释和解决方案。将 ws2811.so 放入我的工作目录并将COPY ws2811.so ./ 添加到我的 Dockerfile 中,就像一个魅力 :-)

以上是关于在 .NET Core Docker 映像中包含共享 C 库 (.SO)的主要内容,如果未能解决你的问题,请参考以下文章

在windows上安装ASP.NET Core 的 Docker 映像

Docker 为 ASP.NET Core 应用程序生成 Docker 映像,并运行多个容器

在 Docker 文件中运行命令

如何在 SQL Server docker 映像之上安装 PowerShell Core?

502 Bad Gateway nginx/1.14.1 elasticbeanstalk .net core app 在 docker 上运行

具有本机依赖关系的 Blazor .NET 6 无法构建为 Docker 映像